brintos

brintos / linux-shallow public Read only

0
0
Text · 12.5 KiB · e83cd05 Raw
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