Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc4 402 lines 9.6 kB view raw
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");