18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Freescale/Motorola Coldfire Queued SPI driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2010 Steven King <sfking@fdwdc.com>
68c2ecf20Sopenharmony_ci*/
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/sched.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci#include <linux/clk.h>
178c2ecf20Sopenharmony_ci#include <linux/err.h>
188c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
198c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/coldfire.h>
228c2ecf20Sopenharmony_ci#include <asm/mcfsim.h>
238c2ecf20Sopenharmony_ci#include <asm/mcfqspi.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define	DRIVER_NAME "mcfqspi"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define	MCFQSPI_BUSCLK			(MCF_BUSCLK / 2)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define	MCFQSPI_QMR			0x00
308c2ecf20Sopenharmony_ci#define		MCFQSPI_QMR_MSTR	0x8000
318c2ecf20Sopenharmony_ci#define		MCFQSPI_QMR_CPOL	0x0200
328c2ecf20Sopenharmony_ci#define		MCFQSPI_QMR_CPHA	0x0100
338c2ecf20Sopenharmony_ci#define	MCFQSPI_QDLYR			0x04
348c2ecf20Sopenharmony_ci#define		MCFQSPI_QDLYR_SPE	0x8000
358c2ecf20Sopenharmony_ci#define	MCFQSPI_QWR			0x08
368c2ecf20Sopenharmony_ci#define		MCFQSPI_QWR_HALT	0x8000
378c2ecf20Sopenharmony_ci#define		MCFQSPI_QWR_WREN	0x4000
388c2ecf20Sopenharmony_ci#define		MCFQSPI_QWR_CSIV	0x1000
398c2ecf20Sopenharmony_ci#define	MCFQSPI_QIR			0x0C
408c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_WCEFB	0x8000
418c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_ABRTB	0x4000
428c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_ABRTL	0x1000
438c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_WCEFE	0x0800
448c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_ABRTE	0x0400
458c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_SPIFE	0x0100
468c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_WCEF	0x0008
478c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_ABRT	0x0004
488c2ecf20Sopenharmony_ci#define		MCFQSPI_QIR_SPIF	0x0001
498c2ecf20Sopenharmony_ci#define	MCFQSPI_QAR			0x010
508c2ecf20Sopenharmony_ci#define		MCFQSPI_QAR_TXBUF	0x00
518c2ecf20Sopenharmony_ci#define		MCFQSPI_QAR_RXBUF	0x10
528c2ecf20Sopenharmony_ci#define		MCFQSPI_QAR_CMDBUF	0x20
538c2ecf20Sopenharmony_ci#define	MCFQSPI_QDR			0x014
548c2ecf20Sopenharmony_ci#define	MCFQSPI_QCR			0x014
558c2ecf20Sopenharmony_ci#define		MCFQSPI_QCR_CONT	0x8000
568c2ecf20Sopenharmony_ci#define		MCFQSPI_QCR_BITSE	0x4000
578c2ecf20Sopenharmony_ci#define		MCFQSPI_QCR_DT		0x2000
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct mcfqspi {
608c2ecf20Sopenharmony_ci	void __iomem *iobase;
618c2ecf20Sopenharmony_ci	int irq;
628c2ecf20Sopenharmony_ci	struct clk *clk;
638c2ecf20Sopenharmony_ci	struct mcfqspi_cs_control *cs_control;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	wait_queue_head_t waitq;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	writew(val, mcfqspi->iobase + MCFQSPI_QMR);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void mcfqspi_wr_qdlyr(struct mcfqspi *mcfqspi, u16 val)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	writew(val, mcfqspi->iobase + MCFQSPI_QDLYR);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic u16 mcfqspi_rd_qdlyr(struct mcfqspi *mcfqspi)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return readw(mcfqspi->iobase + MCFQSPI_QDLYR);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void mcfqspi_wr_qwr(struct mcfqspi *mcfqspi, u16 val)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	writew(val, mcfqspi->iobase + MCFQSPI_QWR);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic void mcfqspi_wr_qir(struct mcfqspi *mcfqspi, u16 val)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	writew(val, mcfqspi->iobase + MCFQSPI_QIR);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void mcfqspi_wr_qar(struct mcfqspi *mcfqspi, u16 val)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	writew(val, mcfqspi->iobase + MCFQSPI_QAR);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic void mcfqspi_wr_qdr(struct mcfqspi *mcfqspi, u16 val)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	writew(val, mcfqspi->iobase + MCFQSPI_QDR);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic u16 mcfqspi_rd_qdr(struct mcfqspi *mcfqspi)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	return readw(mcfqspi->iobase + MCFQSPI_QDR);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void mcfqspi_cs_select(struct mcfqspi *mcfqspi, u8 chip_select,
1098c2ecf20Sopenharmony_ci			    bool cs_high)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	mcfqspi->cs_control->select(mcfqspi->cs_control, chip_select, cs_high);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
1158c2ecf20Sopenharmony_ci				bool cs_high)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	mcfqspi->cs_control->deselect(mcfqspi->cs_control, chip_select, cs_high);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	return (mcfqspi->cs_control->setup) ?
1238c2ecf20Sopenharmony_ci		mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	if (mcfqspi->cs_control->teardown)
1298c2ecf20Sopenharmony_ci		mcfqspi->cs_control->teardown(mcfqspi->cs_control);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic u8 mcfqspi_qmr_baud(u32 speed_hz)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	return clamp((MCFQSPI_BUSCLK + speed_hz - 1) / speed_hz, 2u, 255u);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic bool mcfqspi_qdlyr_spe(struct mcfqspi *mcfqspi)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	return mcfqspi_rd_qdlyr(mcfqspi) & MCFQSPI_QDLYR_SPE;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic irqreturn_t mcfqspi_irq_handler(int this_irq, void *dev_id)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = dev_id;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* clear interrupt */
1478c2ecf20Sopenharmony_ci	mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF);
1488c2ecf20Sopenharmony_ci	wake_up(&mcfqspi->waitq);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic void mcfqspi_transfer_msg8(struct mcfqspi *mcfqspi, unsigned count,
1548c2ecf20Sopenharmony_ci				  const u8 *txbuf, u8 *rxbuf)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	unsigned i, n, offset = 0;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	n = min(count, 16u);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);
1618c2ecf20Sopenharmony_ci	for (i = 0; i < n; ++i)
1628c2ecf20Sopenharmony_ci		mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);
1658c2ecf20Sopenharmony_ci	if (txbuf)
1668c2ecf20Sopenharmony_ci		for (i = 0; i < n; ++i)
1678c2ecf20Sopenharmony_ci			mcfqspi_wr_qdr(mcfqspi, *txbuf++);
1688c2ecf20Sopenharmony_ci	else
1698c2ecf20Sopenharmony_ci		for (i = 0; i < count; ++i)
1708c2ecf20Sopenharmony_ci			mcfqspi_wr_qdr(mcfqspi, 0);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	count -= n;
1738c2ecf20Sopenharmony_ci	if (count) {
1748c2ecf20Sopenharmony_ci		u16 qwr = 0xf08;
1758c2ecf20Sopenharmony_ci		mcfqspi_wr_qwr(mcfqspi, 0x700);
1768c2ecf20Sopenharmony_ci		mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		do {
1798c2ecf20Sopenharmony_ci			wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
1808c2ecf20Sopenharmony_ci			mcfqspi_wr_qwr(mcfqspi, qwr);
1818c2ecf20Sopenharmony_ci			mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
1828c2ecf20Sopenharmony_ci			if (rxbuf) {
1838c2ecf20Sopenharmony_ci				mcfqspi_wr_qar(mcfqspi,
1848c2ecf20Sopenharmony_ci					       MCFQSPI_QAR_RXBUF + offset);
1858c2ecf20Sopenharmony_ci				for (i = 0; i < 8; ++i)
1868c2ecf20Sopenharmony_ci					*rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
1878c2ecf20Sopenharmony_ci			}
1888c2ecf20Sopenharmony_ci			n = min(count, 8u);
1898c2ecf20Sopenharmony_ci			if (txbuf) {
1908c2ecf20Sopenharmony_ci				mcfqspi_wr_qar(mcfqspi,
1918c2ecf20Sopenharmony_ci					       MCFQSPI_QAR_TXBUF + offset);
1928c2ecf20Sopenharmony_ci				for (i = 0; i < n; ++i)
1938c2ecf20Sopenharmony_ci					mcfqspi_wr_qdr(mcfqspi, *txbuf++);
1948c2ecf20Sopenharmony_ci			}
1958c2ecf20Sopenharmony_ci			qwr = (offset ? 0x808 : 0) + ((n - 1) << 8);
1968c2ecf20Sopenharmony_ci			offset ^= 8;
1978c2ecf20Sopenharmony_ci			count -= n;
1988c2ecf20Sopenharmony_ci		} while (count);
1998c2ecf20Sopenharmony_ci		wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
2008c2ecf20Sopenharmony_ci		mcfqspi_wr_qwr(mcfqspi, qwr);
2018c2ecf20Sopenharmony_ci		mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
2028c2ecf20Sopenharmony_ci		if (rxbuf) {
2038c2ecf20Sopenharmony_ci			mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
2048c2ecf20Sopenharmony_ci			for (i = 0; i < 8; ++i)
2058c2ecf20Sopenharmony_ci				*rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
2068c2ecf20Sopenharmony_ci			offset ^= 8;
2078c2ecf20Sopenharmony_ci		}
2088c2ecf20Sopenharmony_ci	} else {
2098c2ecf20Sopenharmony_ci		mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);
2108c2ecf20Sopenharmony_ci		mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
2138c2ecf20Sopenharmony_ci	if (rxbuf) {
2148c2ecf20Sopenharmony_ci		mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
2158c2ecf20Sopenharmony_ci		for (i = 0; i < n; ++i)
2168c2ecf20Sopenharmony_ci			*rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
2218c2ecf20Sopenharmony_ci				   const u16 *txbuf, u16 *rxbuf)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	unsigned i, n, offset = 0;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	n = min(count, 16u);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);
2288c2ecf20Sopenharmony_ci	for (i = 0; i < n; ++i)
2298c2ecf20Sopenharmony_ci		mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);
2328c2ecf20Sopenharmony_ci	if (txbuf)
2338c2ecf20Sopenharmony_ci		for (i = 0; i < n; ++i)
2348c2ecf20Sopenharmony_ci			mcfqspi_wr_qdr(mcfqspi, *txbuf++);
2358c2ecf20Sopenharmony_ci	else
2368c2ecf20Sopenharmony_ci		for (i = 0; i < count; ++i)
2378c2ecf20Sopenharmony_ci			mcfqspi_wr_qdr(mcfqspi, 0);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	count -= n;
2408c2ecf20Sopenharmony_ci	if (count) {
2418c2ecf20Sopenharmony_ci		u16 qwr = 0xf08;
2428c2ecf20Sopenharmony_ci		mcfqspi_wr_qwr(mcfqspi, 0x700);
2438c2ecf20Sopenharmony_ci		mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		do {
2468c2ecf20Sopenharmony_ci			wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
2478c2ecf20Sopenharmony_ci			mcfqspi_wr_qwr(mcfqspi, qwr);
2488c2ecf20Sopenharmony_ci			mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
2498c2ecf20Sopenharmony_ci			if (rxbuf) {
2508c2ecf20Sopenharmony_ci				mcfqspi_wr_qar(mcfqspi,
2518c2ecf20Sopenharmony_ci					       MCFQSPI_QAR_RXBUF + offset);
2528c2ecf20Sopenharmony_ci				for (i = 0; i < 8; ++i)
2538c2ecf20Sopenharmony_ci					*rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
2548c2ecf20Sopenharmony_ci			}
2558c2ecf20Sopenharmony_ci			n = min(count, 8u);
2568c2ecf20Sopenharmony_ci			if (txbuf) {
2578c2ecf20Sopenharmony_ci				mcfqspi_wr_qar(mcfqspi,
2588c2ecf20Sopenharmony_ci					       MCFQSPI_QAR_TXBUF + offset);
2598c2ecf20Sopenharmony_ci				for (i = 0; i < n; ++i)
2608c2ecf20Sopenharmony_ci					mcfqspi_wr_qdr(mcfqspi, *txbuf++);
2618c2ecf20Sopenharmony_ci			}
2628c2ecf20Sopenharmony_ci			qwr = (offset ? 0x808 : 0x000) + ((n - 1) << 8);
2638c2ecf20Sopenharmony_ci			offset ^= 8;
2648c2ecf20Sopenharmony_ci			count -= n;
2658c2ecf20Sopenharmony_ci		} while (count);
2668c2ecf20Sopenharmony_ci		wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
2678c2ecf20Sopenharmony_ci		mcfqspi_wr_qwr(mcfqspi, qwr);
2688c2ecf20Sopenharmony_ci		mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
2698c2ecf20Sopenharmony_ci		if (rxbuf) {
2708c2ecf20Sopenharmony_ci			mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
2718c2ecf20Sopenharmony_ci			for (i = 0; i < 8; ++i)
2728c2ecf20Sopenharmony_ci				*rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
2738c2ecf20Sopenharmony_ci			offset ^= 8;
2748c2ecf20Sopenharmony_ci		}
2758c2ecf20Sopenharmony_ci	} else {
2768c2ecf20Sopenharmony_ci		mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);
2778c2ecf20Sopenharmony_ci		mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
2808c2ecf20Sopenharmony_ci	if (rxbuf) {
2818c2ecf20Sopenharmony_ci		mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
2828c2ecf20Sopenharmony_ci		for (i = 0; i < n; ++i)
2838c2ecf20Sopenharmony_ci			*rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic void mcfqspi_set_cs(struct spi_device *spi, bool enable)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
2908c2ecf20Sopenharmony_ci	bool cs_high = spi->mode & SPI_CS_HIGH;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (enable)
2938c2ecf20Sopenharmony_ci		mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
2948c2ecf20Sopenharmony_ci	else
2958c2ecf20Sopenharmony_ci		mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int mcfqspi_transfer_one(struct spi_master *master,
2998c2ecf20Sopenharmony_ci				struct spi_device *spi,
3008c2ecf20Sopenharmony_ci				struct spi_transfer *t)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
3038c2ecf20Sopenharmony_ci	u16 qmr = MCFQSPI_QMR_MSTR;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	qmr |= t->bits_per_word << 10;
3068c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CPHA)
3078c2ecf20Sopenharmony_ci		qmr |= MCFQSPI_QMR_CPHA;
3088c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CPOL)
3098c2ecf20Sopenharmony_ci		qmr |= MCFQSPI_QMR_CPOL;
3108c2ecf20Sopenharmony_ci	qmr |= mcfqspi_qmr_baud(t->speed_hz);
3118c2ecf20Sopenharmony_ci	mcfqspi_wr_qmr(mcfqspi, qmr);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
3148c2ecf20Sopenharmony_ci	if (t->bits_per_word == 8)
3158c2ecf20Sopenharmony_ci		mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);
3168c2ecf20Sopenharmony_ci	else
3178c2ecf20Sopenharmony_ci		mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
3188c2ecf20Sopenharmony_ci				       t->rx_buf);
3198c2ecf20Sopenharmony_ci	mcfqspi_wr_qir(mcfqspi, 0);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int mcfqspi_setup(struct spi_device *spi)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
3278c2ecf20Sopenharmony_ci			    spi->chip_select, spi->mode & SPI_CS_HIGH);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	dev_dbg(&spi->dev,
3308c2ecf20Sopenharmony_ci			"bits per word %d, chip select %d, speed %d KHz\n",
3318c2ecf20Sopenharmony_ci			spi->bits_per_word, spi->chip_select,
3328c2ecf20Sopenharmony_ci			(MCFQSPI_BUSCLK / mcfqspi_qmr_baud(spi->max_speed_hz))
3338c2ecf20Sopenharmony_ci			/ 1000);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return 0;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int mcfqspi_probe(struct platform_device *pdev)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct spi_master *master;
3418c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi;
3428c2ecf20Sopenharmony_ci	struct mcfqspi_platform_data *pdata;
3438c2ecf20Sopenharmony_ci	int status;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	pdata = dev_get_platdata(&pdev->dev);
3468c2ecf20Sopenharmony_ci	if (!pdata) {
3478c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "platform data is missing\n");
3488c2ecf20Sopenharmony_ci		return -ENOENT;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (!pdata->cs_control) {
3528c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");
3538c2ecf20Sopenharmony_ci		return -EINVAL;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
3578c2ecf20Sopenharmony_ci	if (master == NULL) {
3588c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
3598c2ecf20Sopenharmony_ci		return -ENOMEM;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	mcfqspi = spi_master_get_devdata(master);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	mcfqspi->iobase = devm_platform_ioremap_resource(pdev, 0);
3658c2ecf20Sopenharmony_ci	if (IS_ERR(mcfqspi->iobase)) {
3668c2ecf20Sopenharmony_ci		status = PTR_ERR(mcfqspi->iobase);
3678c2ecf20Sopenharmony_ci		goto fail0;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	mcfqspi->irq = platform_get_irq(pdev, 0);
3718c2ecf20Sopenharmony_ci	if (mcfqspi->irq < 0) {
3728c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "platform_get_irq failed\n");
3738c2ecf20Sopenharmony_ci		status = -ENXIO;
3748c2ecf20Sopenharmony_ci		goto fail0;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	status = devm_request_irq(&pdev->dev, mcfqspi->irq, mcfqspi_irq_handler,
3788c2ecf20Sopenharmony_ci				0, pdev->name, mcfqspi);
3798c2ecf20Sopenharmony_ci	if (status) {
3808c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "request_irq failed\n");
3818c2ecf20Sopenharmony_ci		goto fail0;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	mcfqspi->clk = devm_clk_get(&pdev->dev, "qspi_clk");
3858c2ecf20Sopenharmony_ci	if (IS_ERR(mcfqspi->clk)) {
3868c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "clk_get failed\n");
3878c2ecf20Sopenharmony_ci		status = PTR_ERR(mcfqspi->clk);
3888c2ecf20Sopenharmony_ci		goto fail0;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci	clk_prepare_enable(mcfqspi->clk);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	master->bus_num = pdata->bus_num;
3938c2ecf20Sopenharmony_ci	master->num_chipselect = pdata->num_chipselect;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	mcfqspi->cs_control = pdata->cs_control;
3968c2ecf20Sopenharmony_ci	status = mcfqspi_cs_setup(mcfqspi);
3978c2ecf20Sopenharmony_ci	if (status) {
3988c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "error initializing cs_control\n");
3998c2ecf20Sopenharmony_ci		goto fail1;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	init_waitqueue_head(&mcfqspi->waitq);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
4058c2ecf20Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
4068c2ecf20Sopenharmony_ci	master->setup = mcfqspi_setup;
4078c2ecf20Sopenharmony_ci	master->set_cs = mcfqspi_set_cs;
4088c2ecf20Sopenharmony_ci	master->transfer_one = mcfqspi_transfer_one;
4098c2ecf20Sopenharmony_ci	master->auto_runtime_pm = true;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, master);
4128c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	status = devm_spi_register_master(&pdev->dev, master);
4158c2ecf20Sopenharmony_ci	if (status) {
4168c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "spi_register_master failed\n");
4178c2ecf20Sopenharmony_ci		goto fail2;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cifail2:
4258c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
4268c2ecf20Sopenharmony_ci	mcfqspi_cs_teardown(mcfqspi);
4278c2ecf20Sopenharmony_cifail1:
4288c2ecf20Sopenharmony_ci	clk_disable_unprepare(mcfqspi->clk);
4298c2ecf20Sopenharmony_cifail0:
4308c2ecf20Sopenharmony_ci	spi_master_put(master);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return status;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic int mcfqspi_remove(struct platform_device *pdev)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct spi_master *master = platform_get_drvdata(pdev);
4408c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
4438c2ecf20Sopenharmony_ci	/* disable the hardware (set the baud rate to 0) */
4448c2ecf20Sopenharmony_ci	mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	mcfqspi_cs_teardown(mcfqspi);
4478c2ecf20Sopenharmony_ci	clk_disable_unprepare(mcfqspi->clk);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return 0;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4538c2ecf20Sopenharmony_cistatic int mcfqspi_suspend(struct device *dev)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
4568c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
4578c2ecf20Sopenharmony_ci	int ret;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	ret = spi_master_suspend(master);
4608c2ecf20Sopenharmony_ci	if (ret)
4618c2ecf20Sopenharmony_ci		return ret;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	clk_disable(mcfqspi->clk);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return 0;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int mcfqspi_resume(struct device *dev)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
4718c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	clk_enable(mcfqspi->clk);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	return spi_master_resume(master);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci#endif
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4808c2ecf20Sopenharmony_cistatic int mcfqspi_runtime_suspend(struct device *dev)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
4838c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	clk_disable(mcfqspi->clk);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return 0;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic int mcfqspi_runtime_resume(struct device *dev)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
4938c2ecf20Sopenharmony_ci	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	clk_enable(mcfqspi->clk);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci#endif
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic const struct dev_pm_ops mcfqspi_pm = {
5028c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(mcfqspi_suspend, mcfqspi_resume)
5038c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(mcfqspi_runtime_suspend, mcfqspi_runtime_resume,
5048c2ecf20Sopenharmony_ci			NULL)
5058c2ecf20Sopenharmony_ci};
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic struct platform_driver mcfqspi_driver = {
5088c2ecf20Sopenharmony_ci	.driver.name	= DRIVER_NAME,
5098c2ecf20Sopenharmony_ci	.driver.owner	= THIS_MODULE,
5108c2ecf20Sopenharmony_ci	.driver.pm	= &mcfqspi_pm,
5118c2ecf20Sopenharmony_ci	.probe		= mcfqspi_probe,
5128c2ecf20Sopenharmony_ci	.remove		= mcfqspi_remove,
5138c2ecf20Sopenharmony_ci};
5148c2ecf20Sopenharmony_cimodule_platform_driver(mcfqspi_driver);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
5178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Coldfire QSPI Controller Driver");
5188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5198c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME);
520