513 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Freescale/Motorola Coldfire Queued SPI driver4 *5 * Copyright 2010 Steven King <sfking@fdwdc.com>6*/7 8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/interrupt.h>11#include <linux/errno.h>12#include <linux/platform_device.h>13#include <linux/sched.h>14#include <linux/delay.h>15#include <linux/io.h>16#include <linux/clk.h>17#include <linux/err.h>18#include <linux/spi/spi.h>19#include <linux/pm_runtime.h>20 21#include <asm/coldfire.h>22#include <asm/mcfsim.h>23#include <asm/mcfqspi.h>24 25#define DRIVER_NAME "mcfqspi"26 27#define MCFQSPI_BUSCLK (MCF_BUSCLK / 2)28 29#define MCFQSPI_QMR 0x0030#define MCFQSPI_QMR_MSTR 0x800031#define MCFQSPI_QMR_CPOL 0x020032#define MCFQSPI_QMR_CPHA 0x010033#define MCFQSPI_QDLYR 0x0434#define MCFQSPI_QDLYR_SPE 0x800035#define MCFQSPI_QWR 0x0836#define MCFQSPI_QWR_HALT 0x800037#define MCFQSPI_QWR_WREN 0x400038#define MCFQSPI_QWR_CSIV 0x100039#define MCFQSPI_QIR 0x0C40#define MCFQSPI_QIR_WCEFB 0x800041#define MCFQSPI_QIR_ABRTB 0x400042#define MCFQSPI_QIR_ABRTL 0x100043#define MCFQSPI_QIR_WCEFE 0x080044#define MCFQSPI_QIR_ABRTE 0x040045#define MCFQSPI_QIR_SPIFE 0x010046#define MCFQSPI_QIR_WCEF 0x000847#define MCFQSPI_QIR_ABRT 0x000448#define MCFQSPI_QIR_SPIF 0x000149#define MCFQSPI_QAR 0x01050#define MCFQSPI_QAR_TXBUF 0x0051#define MCFQSPI_QAR_RXBUF 0x1052#define MCFQSPI_QAR_CMDBUF 0x2053#define MCFQSPI_QDR 0x01454#define MCFQSPI_QCR 0x01455#define MCFQSPI_QCR_CONT 0x800056#define MCFQSPI_QCR_BITSE 0x400057#define MCFQSPI_QCR_DT 0x200058 59struct mcfqspi {60 void __iomem *iobase;61 int irq;62 struct clk *clk;63 struct mcfqspi_cs_control *cs_control;64 65 wait_queue_head_t waitq;66};67 68static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)69{70 writew(val, mcfqspi->iobase + MCFQSPI_QMR);71}72 73static void mcfqspi_wr_qdlyr(struct mcfqspi *mcfqspi, u16 val)74{75 writew(val, mcfqspi->iobase + MCFQSPI_QDLYR);76}77 78static u16 mcfqspi_rd_qdlyr(struct mcfqspi *mcfqspi)79{80 return readw(mcfqspi->iobase + MCFQSPI_QDLYR);81}82 83static void mcfqspi_wr_qwr(struct mcfqspi *mcfqspi, u16 val)84{85 writew(val, mcfqspi->iobase + MCFQSPI_QWR);86}87 88static void mcfqspi_wr_qir(struct mcfqspi *mcfqspi, u16 val)89{90 writew(val, mcfqspi->iobase + MCFQSPI_QIR);91}92 93static void mcfqspi_wr_qar(struct mcfqspi *mcfqspi, u16 val)94{95 writew(val, mcfqspi->iobase + MCFQSPI_QAR);96}97 98static void mcfqspi_wr_qdr(struct mcfqspi *mcfqspi, u16 val)99{100 writew(val, mcfqspi->iobase + MCFQSPI_QDR);101}102 103static u16 mcfqspi_rd_qdr(struct mcfqspi *mcfqspi)104{105 return readw(mcfqspi->iobase + MCFQSPI_QDR);106}107 108static void mcfqspi_cs_select(struct mcfqspi *mcfqspi, u8 chip_select,109 bool cs_high)110{111 mcfqspi->cs_control->select(mcfqspi->cs_control, chip_select, cs_high);112}113 114static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,115 bool cs_high)116{117 mcfqspi->cs_control->deselect(mcfqspi->cs_control, chip_select, cs_high);118}119 120static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)121{122 return (mcfqspi->cs_control->setup) ?123 mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;124}125 126static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)127{128 if (mcfqspi->cs_control->teardown)129 mcfqspi->cs_control->teardown(mcfqspi->cs_control);130}131 132static u8 mcfqspi_qmr_baud(u32 speed_hz)133{134 return clamp((MCFQSPI_BUSCLK + speed_hz - 1) / speed_hz, 2u, 255u);135}136 137static bool mcfqspi_qdlyr_spe(struct mcfqspi *mcfqspi)138{139 return mcfqspi_rd_qdlyr(mcfqspi) & MCFQSPI_QDLYR_SPE;140}141 142static irqreturn_t mcfqspi_irq_handler(int this_irq, void *dev_id)143{144 struct mcfqspi *mcfqspi = dev_id;145 146 /* clear interrupt */147 mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF);148 wake_up(&mcfqspi->waitq);149 150 return IRQ_HANDLED;151}152 153static void mcfqspi_transfer_msg8(struct mcfqspi *mcfqspi, unsigned count,154 const u8 *txbuf, u8 *rxbuf)155{156 unsigned i, n, offset = 0;157 158 n = min(count, 16u);159 160 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);161 for (i = 0; i < n; ++i)162 mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);163 164 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);165 if (txbuf)166 for (i = 0; i < n; ++i)167 mcfqspi_wr_qdr(mcfqspi, *txbuf++);168 else169 for (i = 0; i < count; ++i)170 mcfqspi_wr_qdr(mcfqspi, 0);171 172 count -= n;173 if (count) {174 u16 qwr = 0xf08;175 mcfqspi_wr_qwr(mcfqspi, 0x700);176 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);177 178 do {179 wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));180 mcfqspi_wr_qwr(mcfqspi, qwr);181 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);182 if (rxbuf) {183 mcfqspi_wr_qar(mcfqspi,184 MCFQSPI_QAR_RXBUF + offset);185 for (i = 0; i < 8; ++i)186 *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);187 }188 n = min(count, 8u);189 if (txbuf) {190 mcfqspi_wr_qar(mcfqspi,191 MCFQSPI_QAR_TXBUF + offset);192 for (i = 0; i < n; ++i)193 mcfqspi_wr_qdr(mcfqspi, *txbuf++);194 }195 qwr = (offset ? 0x808 : 0) + ((n - 1) << 8);196 offset ^= 8;197 count -= n;198 } while (count);199 wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));200 mcfqspi_wr_qwr(mcfqspi, qwr);201 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);202 if (rxbuf) {203 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);204 for (i = 0; i < 8; ++i)205 *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);206 offset ^= 8;207 }208 } else {209 mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);210 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);211 }212 wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));213 if (rxbuf) {214 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);215 for (i = 0; i < n; ++i)216 *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);217 }218}219 220static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,221 const u16 *txbuf, u16 *rxbuf)222{223 unsigned i, n, offset = 0;224 225 n = min(count, 16u);226 227 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);228 for (i = 0; i < n; ++i)229 mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);230 231 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);232 if (txbuf)233 for (i = 0; i < n; ++i)234 mcfqspi_wr_qdr(mcfqspi, *txbuf++);235 else236 for (i = 0; i < count; ++i)237 mcfqspi_wr_qdr(mcfqspi, 0);238 239 count -= n;240 if (count) {241 u16 qwr = 0xf08;242 mcfqspi_wr_qwr(mcfqspi, 0x700);243 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);244 245 do {246 wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));247 mcfqspi_wr_qwr(mcfqspi, qwr);248 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);249 if (rxbuf) {250 mcfqspi_wr_qar(mcfqspi,251 MCFQSPI_QAR_RXBUF + offset);252 for (i = 0; i < 8; ++i)253 *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);254 }255 n = min(count, 8u);256 if (txbuf) {257 mcfqspi_wr_qar(mcfqspi,258 MCFQSPI_QAR_TXBUF + offset);259 for (i = 0; i < n; ++i)260 mcfqspi_wr_qdr(mcfqspi, *txbuf++);261 }262 qwr = (offset ? 0x808 : 0x000) + ((n - 1) << 8);263 offset ^= 8;264 count -= n;265 } while (count);266 wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));267 mcfqspi_wr_qwr(mcfqspi, qwr);268 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);269 if (rxbuf) {270 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);271 for (i = 0; i < 8; ++i)272 *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);273 offset ^= 8;274 }275 } else {276 mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);277 mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);278 }279 wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));280 if (rxbuf) {281 mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);282 for (i = 0; i < n; ++i)283 *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);284 }285}286 287static void mcfqspi_set_cs(struct spi_device *spi, bool enable)288{289 struct mcfqspi *mcfqspi = spi_controller_get_devdata(spi->controller);290 bool cs_high = spi->mode & SPI_CS_HIGH;291 292 if (enable)293 mcfqspi_cs_select(mcfqspi, spi_get_chipselect(spi, 0), cs_high);294 else295 mcfqspi_cs_deselect(mcfqspi, spi_get_chipselect(spi, 0), cs_high);296}297 298static int mcfqspi_transfer_one(struct spi_controller *host,299 struct spi_device *spi,300 struct spi_transfer *t)301{302 struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);303 u16 qmr = MCFQSPI_QMR_MSTR;304 305 qmr |= t->bits_per_word << 10;306 if (spi->mode & SPI_CPHA)307 qmr |= MCFQSPI_QMR_CPHA;308 if (spi->mode & SPI_CPOL)309 qmr |= MCFQSPI_QMR_CPOL;310 qmr |= mcfqspi_qmr_baud(t->speed_hz);311 mcfqspi_wr_qmr(mcfqspi, qmr);312 313 mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);314 if (t->bits_per_word == 8)315 mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);316 else317 mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,318 t->rx_buf);319 mcfqspi_wr_qir(mcfqspi, 0);320 321 return 0;322}323 324static int mcfqspi_setup(struct spi_device *spi)325{326 mcfqspi_cs_deselect(spi_controller_get_devdata(spi->controller),327 spi_get_chipselect(spi, 0), spi->mode & SPI_CS_HIGH);328 329 dev_dbg(&spi->dev,330 "bits per word %d, chip select %d, speed %d KHz\n",331 spi->bits_per_word, spi_get_chipselect(spi, 0),332 (MCFQSPI_BUSCLK / mcfqspi_qmr_baud(spi->max_speed_hz))333 / 1000);334 335 return 0;336}337 338static int mcfqspi_probe(struct platform_device *pdev)339{340 struct spi_controller *host;341 struct mcfqspi *mcfqspi;342 struct mcfqspi_platform_data *pdata;343 int status;344 345 pdata = dev_get_platdata(&pdev->dev);346 if (!pdata) {347 dev_dbg(&pdev->dev, "platform data is missing\n");348 return -ENOENT;349 }350 351 if (!pdata->cs_control) {352 dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");353 return -EINVAL;354 }355 356 host = spi_alloc_host(&pdev->dev, sizeof(*mcfqspi));357 if (host == NULL) {358 dev_dbg(&pdev->dev, "spi_alloc_host failed\n");359 return -ENOMEM;360 }361 362 mcfqspi = spi_controller_get_devdata(host);363 364 mcfqspi->iobase = devm_platform_ioremap_resource(pdev, 0);365 if (IS_ERR(mcfqspi->iobase)) {366 status = PTR_ERR(mcfqspi->iobase);367 goto fail0;368 }369 370 mcfqspi->irq = platform_get_irq(pdev, 0);371 if (mcfqspi->irq < 0) {372 dev_dbg(&pdev->dev, "platform_get_irq failed\n");373 status = -ENXIO;374 goto fail0;375 }376 377 status = devm_request_irq(&pdev->dev, mcfqspi->irq, mcfqspi_irq_handler,378 0, pdev->name, mcfqspi);379 if (status) {380 dev_dbg(&pdev->dev, "request_irq failed\n");381 goto fail0;382 }383 384 mcfqspi->clk = devm_clk_get_enabled(&pdev->dev, "qspi_clk");385 if (IS_ERR(mcfqspi->clk)) {386 dev_dbg(&pdev->dev, "clk_get failed\n");387 status = PTR_ERR(mcfqspi->clk);388 goto fail0;389 }390 391 host->bus_num = pdata->bus_num;392 host->num_chipselect = pdata->num_chipselect;393 394 mcfqspi->cs_control = pdata->cs_control;395 status = mcfqspi_cs_setup(mcfqspi);396 if (status) {397 dev_dbg(&pdev->dev, "error initializing cs_control\n");398 goto fail0;399 }400 401 init_waitqueue_head(&mcfqspi->waitq);402 403 host->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;404 host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);405 host->setup = mcfqspi_setup;406 host->set_cs = mcfqspi_set_cs;407 host->transfer_one = mcfqspi_transfer_one;408 host->auto_runtime_pm = true;409 410 platform_set_drvdata(pdev, host);411 pm_runtime_enable(&pdev->dev);412 413 status = devm_spi_register_controller(&pdev->dev, host);414 if (status) {415 dev_dbg(&pdev->dev, "devm_spi_register_controller failed\n");416 goto fail1;417 }418 419 dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");420 421 return 0;422 423fail1:424 pm_runtime_disable(&pdev->dev);425 mcfqspi_cs_teardown(mcfqspi);426fail0:427 spi_controller_put(host);428 429 dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");430 431 return status;432}433 434static void mcfqspi_remove(struct platform_device *pdev)435{436 struct spi_controller *host = platform_get_drvdata(pdev);437 struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);438 439 pm_runtime_disable(&pdev->dev);440 /* disable the hardware (set the baud rate to 0) */441 mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);442 443 mcfqspi_cs_teardown(mcfqspi);444}445 446#ifdef CONFIG_PM_SLEEP447static int mcfqspi_suspend(struct device *dev)448{449 struct spi_controller *host = dev_get_drvdata(dev);450 struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);451 int ret;452 453 ret = spi_controller_suspend(host);454 if (ret)455 return ret;456 457 clk_disable(mcfqspi->clk);458 459 return 0;460}461 462static int mcfqspi_resume(struct device *dev)463{464 struct spi_controller *host = dev_get_drvdata(dev);465 struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);466 467 clk_enable(mcfqspi->clk);468 469 return spi_controller_resume(host);470}471#endif472 473#ifdef CONFIG_PM474static int mcfqspi_runtime_suspend(struct device *dev)475{476 struct spi_controller *host = dev_get_drvdata(dev);477 struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);478 479 clk_disable(mcfqspi->clk);480 481 return 0;482}483 484static int mcfqspi_runtime_resume(struct device *dev)485{486 struct spi_controller *host = dev_get_drvdata(dev);487 struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);488 489 clk_enable(mcfqspi->clk);490 491 return 0;492}493#endif494 495static const struct dev_pm_ops mcfqspi_pm = {496 SET_SYSTEM_SLEEP_PM_OPS(mcfqspi_suspend, mcfqspi_resume)497 SET_RUNTIME_PM_OPS(mcfqspi_runtime_suspend, mcfqspi_runtime_resume,498 NULL)499};500 501static struct platform_driver mcfqspi_driver = {502 .driver.name = DRIVER_NAME,503 .driver.pm = &mcfqspi_pm,504 .probe = mcfqspi_probe,505 .remove_new = mcfqspi_remove,506};507module_platform_driver(mcfqspi_driver);508 509MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");510MODULE_DESCRIPTION("Coldfire QSPI Controller Driver");511MODULE_LICENSE("GPL");512MODULE_ALIAS("platform:" DRIVER_NAME);513