linux/drivers/spi/spi-ti-ssp.c
<<
>>
Prefs
   1/*
   2 * Sequencer Serial Port (SSP) based SPI master driver
   3 *
   4 * Copyright (C) 2010 Texas Instruments Inc
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/err.h>
  23#include <linux/completion.h>
  24#include <linux/delay.h>
  25#include <linux/platform_device.h>
  26#include <linux/spi/spi.h>
  27#include <linux/mfd/ti_ssp.h>
  28
  29#define MODE_BITS       (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
  30
  31struct ti_ssp_spi {
  32        struct spi_master               *master;
  33        struct device                   *dev;
  34        spinlock_t                      lock;
  35        struct list_head                msg_queue;
  36        struct completion               complete;
  37        bool                            shutdown;
  38        struct workqueue_struct         *workqueue;
  39        struct work_struct              work;
  40        u8                              mode, bpw;
  41        int                             cs_active;
  42        u32                             pc_en, pc_dis, pc_wr, pc_rd;
  43        void                            (*select)(int cs);
  44};
  45
  46static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
  47{
  48        u32 ret;
  49
  50        ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
  51        return ret;
  52}
  53
  54static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
  55{
  56        ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
  57}
  58
  59static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
  60                       struct spi_transfer *t)
  61{
  62        int count;
  63
  64        if (hw->bpw <= 8) {
  65                u8              *rx = t->rx_buf;
  66                const u8        *tx = t->tx_buf;
  67
  68                for (count = 0; count < t->len; count += 1) {
  69                        if (t->tx_buf)
  70                                ti_ssp_spi_tx(hw, *tx++);
  71                        if (t->rx_buf)
  72                                *rx++ = ti_ssp_spi_rx(hw);
  73                }
  74        } else if (hw->bpw <= 16) {
  75                u16             *rx = t->rx_buf;
  76                const u16       *tx = t->tx_buf;
  77
  78                for (count = 0; count < t->len; count += 2) {
  79                        if (t->tx_buf)
  80                                ti_ssp_spi_tx(hw, *tx++);
  81                        if (t->rx_buf)
  82                                *rx++ = ti_ssp_spi_rx(hw);
  83                }
  84        } else {
  85                u32             *rx = t->rx_buf;
  86                const u32       *tx = t->tx_buf;
  87
  88                for (count = 0; count < t->len; count += 4) {
  89                        if (t->tx_buf)
  90                                ti_ssp_spi_tx(hw, *tx++);
  91                        if (t->rx_buf)
  92                                *rx++ = ti_ssp_spi_rx(hw);
  93                }
  94        }
  95
  96        msg->actual_length += count; /* bytes transferred */
  97
  98        dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
  99                t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
 100                hw->bpw, count, (count < t->len) ? " (under)" : "");
 101
 102        return (count < t->len) ? -EIO : 0; /* left over data */
 103}
 104
 105static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
 106{
 107        cs_active = !!cs_active;
 108        if (cs_active == hw->cs_active)
 109                return;
 110        ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
 111        hw->cs_active = cs_active;
 112}
 113
 114#define __SHIFT_OUT(bits)       (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
 115                                 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
 116#define __SHIFT_IN(bits)        (SSP_OPCODE_SHIFT | SSP_IN_MODE  | \
 117                                 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
 118
 119static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
 120{
 121        int error, idx = 0;
 122        u32 seqram[16];
 123        u32 cs_en, cs_dis, clk;
 124        u32 topbits, botbits;
 125
 126        mode &= MODE_BITS;
 127        if (mode == hw->mode && bpw == hw->bpw)
 128                return 0;
 129
 130        cs_en  = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
 131        cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW  : SSP_CS_HIGH;
 132        clk    = (mode & SPI_CPOL)    ? SSP_CLK_HIGH : SSP_CLK_LOW;
 133
 134        /* Construct instructions */
 135
 136        /* Disable Chip Select */
 137        hw->pc_dis = idx;
 138        seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
 139        seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_dis | clk;
 140
 141        /* Enable Chip Select */
 142        hw->pc_en = idx;
 143        seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
 144        seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_en | clk;
 145
 146        /* Reads and writes need to be split for bpw > 16 */
 147        topbits = (bpw > 16) ? 16 : bpw;
 148        botbits = bpw - topbits;
 149
 150        /* Write */
 151        hw->pc_wr = idx;
 152        seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
 153        if (botbits)
 154                seqram[idx++] = __SHIFT_OUT(botbits)  | SSP_DATA_REG;
 155        seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
 156
 157        /* Read */
 158        hw->pc_rd = idx;
 159        if (botbits)
 160                seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
 161        seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
 162        seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
 163
 164        error = ti_ssp_load(hw->dev, 0, seqram, idx);
 165        if (error < 0)
 166                return error;
 167
 168        error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
 169                                          0 : SSP_EARLY_DIN));
 170        if (error < 0)
 171                return error;
 172
 173        hw->bpw = bpw;
 174        hw->mode = mode;
 175
 176        return error;
 177}
 178
 179static void ti_ssp_spi_work(struct work_struct *work)
 180{
 181        struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
 182
 183        spin_lock(&hw->lock);
 184
 185         while (!list_empty(&hw->msg_queue)) {
 186                struct spi_message      *m;
 187                struct spi_device       *spi;
 188                struct spi_transfer     *t = NULL;
 189                int                     status = 0;
 190
 191                m = container_of(hw->msg_queue.next, struct spi_message,
 192                                 queue);
 193
 194                list_del_init(&m->queue);
 195
 196                spin_unlock(&hw->lock);
 197
 198                spi = m->spi;
 199
 200                if (hw->select)
 201                        hw->select(spi->chip_select);
 202
 203                list_for_each_entry(t, &m->transfers, transfer_list) {
 204                        int bpw = spi->bits_per_word;
 205                        int xfer_status;
 206
 207                        if (t->bits_per_word)
 208                                bpw = t->bits_per_word;
 209
 210                        if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
 211                                break;
 212
 213                        ti_ssp_spi_chip_select(hw, 1);
 214
 215                        xfer_status = ti_ssp_spi_txrx(hw, m, t);
 216                        if (xfer_status < 0)
 217                                status = xfer_status;
 218
 219                        if (t->delay_usecs)
 220                                udelay(t->delay_usecs);
 221
 222                        if (t->cs_change)
 223                                ti_ssp_spi_chip_select(hw, 0);
 224                }
 225
 226                ti_ssp_spi_chip_select(hw, 0);
 227                m->status = status;
 228                m->complete(m->context);
 229
 230                spin_lock(&hw->lock);
 231        }
 232
 233        if (hw->shutdown)
 234                complete(&hw->complete);
 235
 236        spin_unlock(&hw->lock);
 237}
 238
 239static int ti_ssp_spi_setup(struct spi_device *spi)
 240{
 241        if (spi->bits_per_word > 32)
 242                return -EINVAL;
 243
 244        return 0;
 245}
 246
 247static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
 248{
 249        struct ti_ssp_spi       *hw;
 250        struct spi_transfer     *t;
 251        int                     error = 0;
 252
 253        m->actual_length = 0;
 254        m->status = -EINPROGRESS;
 255
 256        hw = spi_master_get_devdata(spi->master);
 257
 258        if (list_empty(&m->transfers) || !m->complete)
 259                return -EINVAL;
 260
 261        list_for_each_entry(t, &m->transfers, transfer_list) {
 262                if (t->len && !(t->rx_buf || t->tx_buf)) {
 263                        dev_err(&spi->dev, "invalid xfer, no buffer\n");
 264                        return -EINVAL;
 265                }
 266
 267                if (t->len && t->rx_buf && t->tx_buf) {
 268                        dev_err(&spi->dev, "invalid xfer, full duplex\n");
 269                        return -EINVAL;
 270                }
 271
 272                if (t->bits_per_word > 32) {
 273                        dev_err(&spi->dev, "invalid xfer width %d\n",
 274                                t->bits_per_word);
 275                        return -EINVAL;
 276                }
 277        }
 278
 279        spin_lock(&hw->lock);
 280        if (hw->shutdown) {
 281                error = -ESHUTDOWN;
 282                goto error_unlock;
 283        }
 284        list_add_tail(&m->queue, &hw->msg_queue);
 285        queue_work(hw->workqueue, &hw->work);
 286error_unlock:
 287        spin_unlock(&hw->lock);
 288        return error;
 289}
 290
 291static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
 292{
 293        const struct ti_ssp_spi_data *pdata;
 294        struct ti_ssp_spi *hw;
 295        struct spi_master *master;
 296        struct device *dev = &pdev->dev;
 297        int error = 0;
 298
 299        pdata = dev->platform_data;
 300        if (!pdata) {
 301                dev_err(dev, "platform data not found\n");
 302                return -EINVAL;
 303        }
 304
 305        master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
 306        if (!master) {
 307                dev_err(dev, "cannot allocate SPI master\n");
 308                return -ENOMEM;
 309        }
 310
 311        hw = spi_master_get_devdata(master);
 312        platform_set_drvdata(pdev, hw);
 313
 314        hw->master = master;
 315        hw->dev = dev;
 316        hw->select = pdata->select;
 317
 318        spin_lock_init(&hw->lock);
 319        init_completion(&hw->complete);
 320        INIT_LIST_HEAD(&hw->msg_queue);
 321        INIT_WORK(&hw->work, ti_ssp_spi_work);
 322
 323        hw->workqueue = create_singlethread_workqueue(dev_name(dev));
 324        if (!hw->workqueue) {
 325                error = -ENOMEM;
 326                dev_err(dev, "work queue creation failed\n");
 327                goto error_wq;
 328        }
 329
 330        error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
 331        if (error < 0) {
 332                dev_err(dev, "io setup failed\n");
 333                goto error_iosel;
 334        }
 335
 336        master->bus_num         = pdev->id;
 337        master->num_chipselect  = pdata->num_cs;
 338        master->mode_bits       = MODE_BITS;
 339        master->flags           = SPI_MASTER_HALF_DUPLEX;
 340        master->setup           = ti_ssp_spi_setup;
 341        master->transfer        = ti_ssp_spi_transfer;
 342
 343        error = spi_register_master(master);
 344        if (error) {
 345                dev_err(dev, "master registration failed\n");
 346                goto error_reg;
 347        }
 348
 349        return 0;
 350
 351error_reg:
 352error_iosel:
 353        destroy_workqueue(hw->workqueue);
 354error_wq:
 355        spi_master_put(master);
 356        return error;
 357}
 358
 359static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
 360{
 361        struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
 362        int error;
 363
 364        hw->shutdown = 1;
 365        while (!list_empty(&hw->msg_queue)) {
 366                error = wait_for_completion_interruptible(&hw->complete);
 367                if (error < 0) {
 368                        hw->shutdown = 0;
 369                        return error;
 370                }
 371        }
 372        destroy_workqueue(hw->workqueue);
 373        spi_unregister_master(hw->master);
 374
 375        return 0;
 376}
 377
 378static struct platform_driver ti_ssp_spi_driver = {
 379        .probe          = ti_ssp_spi_probe,
 380        .remove         = __devexit_p(ti_ssp_spi_remove),
 381        .driver         = {
 382                .name   = "ti-ssp-spi",
 383                .owner  = THIS_MODULE,
 384        },
 385};
 386
 387static int __init ti_ssp_spi_init(void)
 388{
 389        return platform_driver_register(&ti_ssp_spi_driver);
 390}
 391module_init(ti_ssp_spi_init);
 392
 393static void __exit ti_ssp_spi_exit(void)
 394{
 395        platform_driver_unregister(&ti_ssp_spi_driver);
 396}
 397module_exit(ti_ssp_spi_exit);
 398
 399MODULE_DESCRIPTION("SSP SPI Master");
 400MODULE_AUTHOR("Cyril Chemparathy");
 401MODULE_LICENSE("GPL");
 402MODULE_ALIAS("platform:ti-ssp-spi");
 403