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/module.h>
  26#include <linux/platform_device.h>
  27#include <linux/spi/spi.h>
  28#include <linux/mfd/ti_ssp.h>
  29
  30#define MODE_BITS       (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
  31
  32struct ti_ssp_spi {
  33        struct spi_master               *master;
  34        struct device                   *dev;
  35        spinlock_t                      lock;
  36        struct list_head                msg_queue;
  37        struct completion               complete;
  38        bool                            shutdown;
  39        struct workqueue_struct         *workqueue;
  40        struct work_struct              work;
  41        u8                              mode, bpw;
  42        int                             cs_active;
  43        u32                             pc_en, pc_dis, pc_wr, pc_rd;
  44        void                            (*select)(int cs);
  45};
  46
  47static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
  48{
  49        u32 ret;
  50
  51        ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
  52        return ret;
  53}
  54
  55static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
  56{
  57        ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
  58}
  59
  60static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
  61                       struct spi_transfer *t)
  62{
  63        int count;
  64
  65        if (hw->bpw <= 8) {
  66                u8              *rx = t->rx_buf;
  67                const u8        *tx = t->tx_buf;
  68
  69                for (count = 0; count < t->len; count += 1) {
  70                        if (t->tx_buf)
  71                                ti_ssp_spi_tx(hw, *tx++);
  72                        if (t->rx_buf)
  73                                *rx++ = ti_ssp_spi_rx(hw);
  74                }
  75        } else if (hw->bpw <= 16) {
  76                u16             *rx = t->rx_buf;
  77                const u16       *tx = t->tx_buf;
  78
  79                for (count = 0; count < t->len; count += 2) {
  80                        if (t->tx_buf)
  81                                ti_ssp_spi_tx(hw, *tx++);
  82                        if (t->rx_buf)
  83                                *rx++ = ti_ssp_spi_rx(hw);
  84                }
  85        } else {
  86                u32             *rx = t->rx_buf;
  87                const u32       *tx = t->tx_buf;
  88
  89                for (count = 0; count < t->len; count += 4) {
  90                        if (t->tx_buf)
  91                                ti_ssp_spi_tx(hw, *tx++);
  92                        if (t->rx_buf)
  93                                *rx++ = ti_ssp_spi_rx(hw);
  94                }
  95        }
  96
  97        msg->actual_length += count; /* bytes transferred */
  98
  99        dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
 100                t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
 101                hw->bpw, count, (count < t->len) ? " (under)" : "");
 102
 103        return (count < t->len) ? -EIO : 0; /* left over data */
 104}
 105
 106static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
 107{
 108        cs_active = !!cs_active;
 109        if (cs_active == hw->cs_active)
 110                return;
 111        ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
 112        hw->cs_active = cs_active;
 113}
 114
 115#define __SHIFT_OUT(bits)       (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
 116                                 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
 117#define __SHIFT_IN(bits)        (SSP_OPCODE_SHIFT | SSP_IN_MODE  | \
 118                                 cs_en | clk | SSP_COUNT((bits) * 2 - 1))
 119
 120static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
 121{
 122        int error, idx = 0;
 123        u32 seqram[16];
 124        u32 cs_en, cs_dis, clk;
 125        u32 topbits, botbits;
 126
 127        mode &= MODE_BITS;
 128        if (mode == hw->mode && bpw == hw->bpw)
 129                return 0;
 130
 131        cs_en  = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
 132        cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW  : SSP_CS_HIGH;
 133        clk    = (mode & SPI_CPOL)    ? SSP_CLK_HIGH : SSP_CLK_LOW;
 134
 135        /* Construct instructions */
 136
 137        /* Disable Chip Select */
 138        hw->pc_dis = idx;
 139        seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
 140        seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_dis | clk;
 141
 142        /* Enable Chip Select */
 143        hw->pc_en = idx;
 144        seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
 145        seqram[idx++] = SSP_OPCODE_STOP   | SSP_OUT_MODE | cs_en | clk;
 146
 147        /* Reads and writes need to be split for bpw > 16 */
 148        topbits = (bpw > 16) ? 16 : bpw;
 149        botbits = bpw - topbits;
 150
 151        /* Write */
 152        hw->pc_wr = idx;
 153        seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
 154        if (botbits)
 155                seqram[idx++] = __SHIFT_OUT(botbits)  | SSP_DATA_REG;
 156        seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
 157
 158        /* Read */
 159        hw->pc_rd = idx;
 160        if (botbits)
 161                seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
 162        seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
 163        seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
 164
 165        error = ti_ssp_load(hw->dev, 0, seqram, idx);
 166        if (error < 0)
 167                return error;
 168
 169        error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
 170                                          0 : SSP_EARLY_DIN));
 171        if (error < 0)
 172                return error;
 173
 174        hw->bpw = bpw;
 175        hw->mode = mode;
 176
 177        return error;
 178}
 179
 180static void ti_ssp_spi_work(struct work_struct *work)
 181{
 182        struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
 183
 184        spin_lock(&hw->lock);
 185
 186         while (!list_empty(&hw->msg_queue)) {
 187                struct spi_message      *m;
 188                struct spi_device       *spi;
 189                struct spi_transfer     *t = NULL;
 190                int                     status = 0;
 191
 192                m = container_of(hw->msg_queue.next, struct spi_message,
 193                                 queue);
 194
 195                list_del_init(&m->queue);
 196
 197                spin_unlock(&hw->lock);
 198
 199                spi = m->spi;
 200
 201                if (hw->select)
 202                        hw->select(spi->chip_select);
 203
 204                list_for_each_entry(t, &m->transfers, transfer_list) {
 205                        int bpw = spi->bits_per_word;
 206                        int xfer_status;
 207
 208                        if (t->bits_per_word)
 209                                bpw = t->bits_per_word;
 210
 211                        if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
 212                                break;
 213
 214                        ti_ssp_spi_chip_select(hw, 1);
 215
 216                        xfer_status = ti_ssp_spi_txrx(hw, m, t);
 217                        if (xfer_status < 0)
 218                                status = xfer_status;
 219
 220                        if (t->delay_usecs)
 221                                udelay(t->delay_usecs);
 222
 223                        if (t->cs_change)
 224                                ti_ssp_spi_chip_select(hw, 0);
 225                }
 226
 227                ti_ssp_spi_chip_select(hw, 0);
 228                m->status = status;
 229                m->complete(m->context);
 230
 231                spin_lock(&hw->lock);
 232        }
 233
 234        if (hw->shutdown)
 235                complete(&hw->complete);
 236
 237        spin_unlock(&hw->lock);
 238}
 239
 240static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
 241{
 242        struct ti_ssp_spi       *hw;
 243        struct spi_transfer     *t;
 244        int                     error = 0;
 245
 246        m->actual_length = 0;
 247        m->status = -EINPROGRESS;
 248
 249        hw = spi_master_get_devdata(spi->master);
 250
 251        if (list_empty(&m->transfers) || !m->complete)
 252                return -EINVAL;
 253
 254        list_for_each_entry(t, &m->transfers, transfer_list) {
 255                if (t->len && !(t->rx_buf || t->tx_buf)) {
 256                        dev_err(&spi->dev, "invalid xfer, no buffer\n");
 257                        return -EINVAL;
 258                }
 259
 260                if (t->len && t->rx_buf && t->tx_buf) {
 261                        dev_err(&spi->dev, "invalid xfer, full duplex\n");
 262                        return -EINVAL;
 263                }
 264        }
 265
 266        spin_lock(&hw->lock);
 267        if (hw->shutdown) {
 268                error = -ESHUTDOWN;
 269                goto error_unlock;
 270        }
 271        list_add_tail(&m->queue, &hw->msg_queue);
 272        queue_work(hw->workqueue, &hw->work);
 273error_unlock:
 274        spin_unlock(&hw->lock);
 275        return error;
 276}
 277
 278static int ti_ssp_spi_probe(struct platform_device *pdev)
 279{
 280        const struct ti_ssp_spi_data *pdata;
 281        struct ti_ssp_spi *hw;
 282        struct spi_master *master;
 283        struct device *dev = &pdev->dev;
 284        int error = 0;
 285
 286        pdata = dev_get_platdata(dev);
 287        if (!pdata) {
 288                dev_err(dev, "platform data not found\n");
 289                return -EINVAL;
 290        }
 291
 292        master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
 293        if (!master) {
 294                dev_err(dev, "cannot allocate SPI master\n");
 295                return -ENOMEM;
 296        }
 297
 298        hw = spi_master_get_devdata(master);
 299        platform_set_drvdata(pdev, hw);
 300
 301        hw->master = master;
 302        hw->dev = dev;
 303        hw->select = pdata->select;
 304
 305        spin_lock_init(&hw->lock);
 306        init_completion(&hw->complete);
 307        INIT_LIST_HEAD(&hw->msg_queue);
 308        INIT_WORK(&hw->work, ti_ssp_spi_work);
 309
 310        hw->workqueue = create_singlethread_workqueue(dev_name(dev));
 311        if (!hw->workqueue) {
 312                error = -ENOMEM;
 313                dev_err(dev, "work queue creation failed\n");
 314                goto error_wq;
 315        }
 316
 317        error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
 318        if (error < 0) {
 319                dev_err(dev, "io setup failed\n");
 320                goto error_iosel;
 321        }
 322
 323        master->bus_num         = pdev->id;
 324        master->num_chipselect  = pdata->num_cs;
 325        master->mode_bits       = MODE_BITS;
 326        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
 327        master->flags           = SPI_MASTER_HALF_DUPLEX;
 328        master->transfer        = ti_ssp_spi_transfer;
 329
 330        error = spi_register_master(master);
 331        if (error) {
 332                dev_err(dev, "master registration failed\n");
 333                goto error_reg;
 334        }
 335
 336        return 0;
 337
 338error_reg:
 339error_iosel:
 340        destroy_workqueue(hw->workqueue);
 341error_wq:
 342        spi_master_put(master);
 343        return error;
 344}
 345
 346static int ti_ssp_spi_remove(struct platform_device *pdev)
 347{
 348        struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
 349        int error;
 350
 351        hw->shutdown = 1;
 352        while (!list_empty(&hw->msg_queue)) {
 353                error = wait_for_completion_interruptible(&hw->complete);
 354                if (error < 0) {
 355                        hw->shutdown = 0;
 356                        return error;
 357                }
 358        }
 359        destroy_workqueue(hw->workqueue);
 360        spi_unregister_master(hw->master);
 361
 362        return 0;
 363}
 364
 365static struct platform_driver ti_ssp_spi_driver = {
 366        .probe          = ti_ssp_spi_probe,
 367        .remove         = ti_ssp_spi_remove,
 368        .driver         = {
 369                .name   = "ti-ssp-spi",
 370                .owner  = THIS_MODULE,
 371        },
 372};
 373module_platform_driver(ti_ssp_spi_driver);
 374
 375MODULE_DESCRIPTION("SSP SPI Master");
 376MODULE_AUTHOR("Cyril Chemparathy");
 377MODULE_LICENSE("GPL");
 378MODULE_ALIAS("platform:ti-ssp-spi");
 379
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.