xref: /linux/drivers/spi/spi-bcmbca-hsspi.c (revision 879a879c216a41f5403d8d3dbc204a48501912bf)
1a38a2233SWilliam Zhang // SPDX-License-Identifier: GPL-2.0-only
2a38a2233SWilliam Zhang /*
3a38a2233SWilliam Zhang  * Broadcom BCMBCA High Speed SPI Controller driver
4a38a2233SWilliam Zhang  *
5a38a2233SWilliam Zhang  * Copyright 2000-2010 Broadcom Corporation
6*879a879cSJonas Gorski  * Copyright 2012-2013 Jonas Gorski <jonas.gorski@gmail.com>
7a38a2233SWilliam Zhang  * Copyright 2019-2022 Broadcom Ltd
8a38a2233SWilliam Zhang  */
9a38a2233SWilliam Zhang 
10a38a2233SWilliam Zhang #include <linux/kernel.h>
11a38a2233SWilliam Zhang #include <linux/init.h>
12a38a2233SWilliam Zhang #include <linux/io.h>
13a38a2233SWilliam Zhang #include <linux/clk.h>
14a38a2233SWilliam Zhang #include <linux/module.h>
15a38a2233SWilliam Zhang #include <linux/platform_device.h>
16a38a2233SWilliam Zhang #include <linux/delay.h>
17a38a2233SWilliam Zhang #include <linux/dma-mapping.h>
18a38a2233SWilliam Zhang #include <linux/err.h>
19a38a2233SWilliam Zhang #include <linux/interrupt.h>
20a38a2233SWilliam Zhang #include <linux/spi/spi.h>
21a38a2233SWilliam Zhang #include <linux/mutex.h>
22a38a2233SWilliam Zhang #include <linux/of.h>
23a38a2233SWilliam Zhang #include <linux/spi/spi-mem.h>
24a38a2233SWilliam Zhang #include <linux/pm_runtime.h>
25a38a2233SWilliam Zhang 
26a38a2233SWilliam Zhang #define HSSPI_GLOBAL_CTRL_REG			0x0
27a38a2233SWilliam Zhang #define GLOBAL_CTRL_CS_POLARITY_SHIFT		0
28a38a2233SWilliam Zhang #define GLOBAL_CTRL_CS_POLARITY_MASK		0x000000ff
29a38a2233SWilliam Zhang #define GLOBAL_CTRL_PLL_CLK_CTRL_SHIFT		8
30a38a2233SWilliam Zhang #define GLOBAL_CTRL_PLL_CLK_CTRL_MASK		0x0000ff00
31a38a2233SWilliam Zhang #define GLOBAL_CTRL_CLK_GATE_SSOFF		BIT(16)
32a38a2233SWilliam Zhang #define GLOBAL_CTRL_CLK_POLARITY		BIT(17)
33a38a2233SWilliam Zhang #define GLOBAL_CTRL_MOSI_IDLE			BIT(18)
34a38a2233SWilliam Zhang 
35a38a2233SWilliam Zhang #define HSSPI_GLOBAL_EXT_TRIGGER_REG		0x4
36a38a2233SWilliam Zhang 
37a38a2233SWilliam Zhang #define HSSPI_INT_STATUS_REG			0x8
38a38a2233SWilliam Zhang #define HSSPI_INT_STATUS_MASKED_REG		0xc
39a38a2233SWilliam Zhang #define HSSPI_INT_MASK_REG			0x10
40a38a2233SWilliam Zhang 
41a38a2233SWilliam Zhang #define HSSPI_PINGx_CMD_DONE(i)			BIT((i * 8) + 0)
42a38a2233SWilliam Zhang #define HSSPI_PINGx_RX_OVER(i)			BIT((i * 8) + 1)
43a38a2233SWilliam Zhang #define HSSPI_PINGx_TX_UNDER(i)			BIT((i * 8) + 2)
44a38a2233SWilliam Zhang #define HSSPI_PINGx_POLL_TIMEOUT(i)		BIT((i * 8) + 3)
45a38a2233SWilliam Zhang #define HSSPI_PINGx_CTRL_INVAL(i)		BIT((i * 8) + 4)
46a38a2233SWilliam Zhang 
47a38a2233SWilliam Zhang #define HSSPI_INT_CLEAR_ALL			0xff001f1f
48a38a2233SWilliam Zhang 
49a38a2233SWilliam Zhang #define HSSPI_PINGPONG_COMMAND_REG(x)		(0x80 + (x) * 0x40)
50a38a2233SWilliam Zhang #define PINGPONG_CMD_COMMAND_MASK		0xf
51a38a2233SWilliam Zhang #define PINGPONG_COMMAND_NOOP			0
52a38a2233SWilliam Zhang #define PINGPONG_COMMAND_START_NOW		1
53a38a2233SWilliam Zhang #define PINGPONG_COMMAND_START_TRIGGER		2
54a38a2233SWilliam Zhang #define PINGPONG_COMMAND_HALT			3
55a38a2233SWilliam Zhang #define PINGPONG_COMMAND_FLUSH			4
56a38a2233SWilliam Zhang #define PINGPONG_CMD_PROFILE_SHIFT		8
57a38a2233SWilliam Zhang #define PINGPONG_CMD_SS_SHIFT			12
58a38a2233SWilliam Zhang 
59a38a2233SWilliam Zhang #define HSSPI_PINGPONG_STATUS_REG(x)		(0x84 + (x) * 0x40)
60a38a2233SWilliam Zhang #define HSSPI_PINGPONG_STATUS_SRC_BUSY          BIT(1)
61a38a2233SWilliam Zhang 
62a38a2233SWilliam Zhang #define HSSPI_PROFILE_CLK_CTRL_REG(x)		(0x100 + (x) * 0x20)
63a38a2233SWilliam Zhang #define CLK_CTRL_FREQ_CTRL_MASK			0x0000ffff
64a38a2233SWilliam Zhang #define CLK_CTRL_SPI_CLK_2X_SEL			BIT(14)
65a38a2233SWilliam Zhang #define CLK_CTRL_ACCUM_RST_ON_LOOP		BIT(15)
66a38a2233SWilliam Zhang #define CLK_CTRL_CLK_POLARITY			BIT(16)
67a38a2233SWilliam Zhang 
68a38a2233SWilliam Zhang #define HSSPI_PROFILE_SIGNAL_CTRL_REG(x)	(0x104 + (x) * 0x20)
69a38a2233SWilliam Zhang #define SIGNAL_CTRL_LATCH_RISING		BIT(12)
70a38a2233SWilliam Zhang #define SIGNAL_CTRL_LAUNCH_RISING		BIT(13)
71a38a2233SWilliam Zhang #define SIGNAL_CTRL_ASYNC_INPUT_PATH		BIT(16)
72a38a2233SWilliam Zhang 
73a38a2233SWilliam Zhang #define HSSPI_PROFILE_MODE_CTRL_REG(x)		(0x108 + (x) * 0x20)
74a38a2233SWilliam Zhang #define MODE_CTRL_MULTIDATA_RD_STRT_SHIFT	8
75a38a2233SWilliam Zhang #define MODE_CTRL_MULTIDATA_WR_STRT_SHIFT	12
76a38a2233SWilliam Zhang #define MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT	16
77a38a2233SWilliam Zhang #define MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT	18
78a38a2233SWilliam Zhang #define MODE_CTRL_MODE_3WIRE			BIT(20)
79a38a2233SWilliam Zhang #define MODE_CTRL_PREPENDBYTE_CNT_SHIFT		24
80a38a2233SWilliam Zhang 
81a38a2233SWilliam Zhang #define HSSPI_FIFO_REG(x)			(0x200 + (x) * 0x200)
82a38a2233SWilliam Zhang 
83a38a2233SWilliam Zhang #define HSSPI_OP_MULTIBIT			BIT(11)
84a38a2233SWilliam Zhang #define HSSPI_OP_CODE_SHIFT			13
85a38a2233SWilliam Zhang #define HSSPI_OP_SLEEP				(0 << HSSPI_OP_CODE_SHIFT)
86a38a2233SWilliam Zhang #define HSSPI_OP_READ_WRITE			(1 << HSSPI_OP_CODE_SHIFT)
87a38a2233SWilliam Zhang #define HSSPI_OP_WRITE				(2 << HSSPI_OP_CODE_SHIFT)
88a38a2233SWilliam Zhang #define HSSPI_OP_READ				(3 << HSSPI_OP_CODE_SHIFT)
89a38a2233SWilliam Zhang #define HSSPI_OP_SETIRQ				(4 << HSSPI_OP_CODE_SHIFT)
90a38a2233SWilliam Zhang 
91a38a2233SWilliam Zhang #define HSSPI_BUFFER_LEN			512
92a38a2233SWilliam Zhang #define HSSPI_OPCODE_LEN			2
93a38a2233SWilliam Zhang 
94a38a2233SWilliam Zhang #define HSSPI_MAX_PREPEND_LEN			15
95a38a2233SWilliam Zhang 
96a38a2233SWilliam Zhang #define HSSPI_MAX_SYNC_CLOCK			30000000
97a38a2233SWilliam Zhang 
98a38a2233SWilliam Zhang #define HSSPI_SPI_MAX_CS			8
99a38a2233SWilliam Zhang #define HSSPI_BUS_NUM				1	/* 0 is legacy SPI */
100a38a2233SWilliam Zhang #define HSSPI_POLL_STATUS_TIMEOUT_MS	100
101a38a2233SWilliam Zhang 
102a38a2233SWilliam Zhang #define HSSPI_WAIT_MODE_POLLING		0
103a38a2233SWilliam Zhang #define HSSPI_WAIT_MODE_INTR		1
104a38a2233SWilliam Zhang #define HSSPI_WAIT_MODE_MAX			HSSPI_WAIT_MODE_INTR
105a38a2233SWilliam Zhang 
106a38a2233SWilliam Zhang #define SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT		0
107a38a2233SWilliam Zhang #define SPIM_CTRL_CS_OVERRIDE_SEL_MASK		0xff
108a38a2233SWilliam Zhang #define SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT		8
109a38a2233SWilliam Zhang #define SPIM_CTRL_CS_OVERRIDE_VAL_MASK		0xff
110a38a2233SWilliam Zhang 
111a38a2233SWilliam Zhang struct bcmbca_hsspi {
112a38a2233SWilliam Zhang 	struct completion done;
113a38a2233SWilliam Zhang 	struct mutex bus_mutex;
114a38a2233SWilliam Zhang 	struct mutex msg_mutex;
115a38a2233SWilliam Zhang 	struct platform_device *pdev;
116a38a2233SWilliam Zhang 	struct clk *clk;
117a38a2233SWilliam Zhang 	struct clk *pll_clk;
118a38a2233SWilliam Zhang 	void __iomem *regs;
119a38a2233SWilliam Zhang 	void __iomem *spim_ctrl;
120a38a2233SWilliam Zhang 	u8 __iomem *fifo;
121a38a2233SWilliam Zhang 	u32 speed_hz;
122a38a2233SWilliam Zhang 	u8 cs_polarity;
123a38a2233SWilliam Zhang 	u32 wait_mode;
124a38a2233SWilliam Zhang };
125a38a2233SWilliam Zhang 
126a38a2233SWilliam Zhang static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
127a38a2233SWilliam Zhang 			 char *buf)
128a38a2233SWilliam Zhang {
129a38a2233SWilliam Zhang 	struct spi_controller *ctrl = dev_get_drvdata(dev);
130a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
131a38a2233SWilliam Zhang 
132a38a2233SWilliam Zhang 	return sprintf(buf, "%d\n", bs->wait_mode);
133a38a2233SWilliam Zhang }
134a38a2233SWilliam Zhang 
135a38a2233SWilliam Zhang static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
136a38a2233SWilliam Zhang 			  const char *buf, size_t count)
137a38a2233SWilliam Zhang {
138a38a2233SWilliam Zhang 	struct spi_controller *ctrl = dev_get_drvdata(dev);
139a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
140a38a2233SWilliam Zhang 	u32 val;
141a38a2233SWilliam Zhang 
142a38a2233SWilliam Zhang 	if (kstrtou32(buf, 10, &val))
143a38a2233SWilliam Zhang 		return -EINVAL;
144a38a2233SWilliam Zhang 
145a38a2233SWilliam Zhang 	if (val > HSSPI_WAIT_MODE_MAX) {
146a38a2233SWilliam Zhang 		dev_warn(dev, "invalid wait mode %u\n", val);
147a38a2233SWilliam Zhang 		return -EINVAL;
148a38a2233SWilliam Zhang 	}
149a38a2233SWilliam Zhang 
150a38a2233SWilliam Zhang 	mutex_lock(&bs->msg_mutex);
151a38a2233SWilliam Zhang 	bs->wait_mode = val;
152a38a2233SWilliam Zhang 	/* clear interrupt status to avoid spurious int on next transfer */
153a38a2233SWilliam Zhang 	if (val == HSSPI_WAIT_MODE_INTR)
154a38a2233SWilliam Zhang 		__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
155a38a2233SWilliam Zhang 	mutex_unlock(&bs->msg_mutex);
156a38a2233SWilliam Zhang 
157a38a2233SWilliam Zhang 	return count;
158a38a2233SWilliam Zhang }
159a38a2233SWilliam Zhang 
160a38a2233SWilliam Zhang static DEVICE_ATTR_RW(wait_mode);
161a38a2233SWilliam Zhang 
162a38a2233SWilliam Zhang static struct attribute *bcmbca_hsspi_attrs[] = {
163a38a2233SWilliam Zhang 	&dev_attr_wait_mode.attr,
164a38a2233SWilliam Zhang 	NULL,
165a38a2233SWilliam Zhang };
166a38a2233SWilliam Zhang 
167a38a2233SWilliam Zhang static const struct attribute_group bcmbca_hsspi_group = {
168a38a2233SWilliam Zhang 	.attrs = bcmbca_hsspi_attrs,
169a38a2233SWilliam Zhang };
170a38a2233SWilliam Zhang 
171a38a2233SWilliam Zhang static void bcmbca_hsspi_set_cs(struct bcmbca_hsspi *bs, unsigned int cs,
172a38a2233SWilliam Zhang 				 bool active)
173a38a2233SWilliam Zhang {
174a38a2233SWilliam Zhang 	u32 reg;
175a38a2233SWilliam Zhang 
176a38a2233SWilliam Zhang 	/* No cs orerriden needed for SS7 internal cs on pcm based voice dev */
177a38a2233SWilliam Zhang 	if (cs == 7)
178a38a2233SWilliam Zhang 		return;
179a38a2233SWilliam Zhang 
180a38a2233SWilliam Zhang 	mutex_lock(&bs->bus_mutex);
181a38a2233SWilliam Zhang 
182a38a2233SWilliam Zhang 	reg = __raw_readl(bs->spim_ctrl);
183a38a2233SWilliam Zhang 	if (active)
184a38a2233SWilliam Zhang 		reg |= BIT(cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
185a38a2233SWilliam Zhang 	else
186a38a2233SWilliam Zhang 		reg &= ~BIT(cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
187a38a2233SWilliam Zhang 
188a38a2233SWilliam Zhang 	__raw_writel(reg, bs->spim_ctrl);
189a38a2233SWilliam Zhang 
190a38a2233SWilliam Zhang 	mutex_unlock(&bs->bus_mutex);
191a38a2233SWilliam Zhang }
192a38a2233SWilliam Zhang 
193a38a2233SWilliam Zhang static void bcmbca_hsspi_set_clk(struct bcmbca_hsspi *bs,
194a38a2233SWilliam Zhang 				  struct spi_device *spi, int hz)
195a38a2233SWilliam Zhang {
1969e264f3fSAmit Kumar Mahapatra via Alsa-devel 	unsigned int profile = spi_get_chipselect(spi, 0);
197a38a2233SWilliam Zhang 	u32 reg;
198a38a2233SWilliam Zhang 
199a38a2233SWilliam Zhang 	reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
200a38a2233SWilliam Zhang 	__raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
201a38a2233SWilliam Zhang 		     bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));
202a38a2233SWilliam Zhang 
203a38a2233SWilliam Zhang 	reg = __raw_readl(bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
204a38a2233SWilliam Zhang 	if (hz > HSSPI_MAX_SYNC_CLOCK)
205a38a2233SWilliam Zhang 		reg |= SIGNAL_CTRL_ASYNC_INPUT_PATH;
206a38a2233SWilliam Zhang 	else
207a38a2233SWilliam Zhang 		reg &= ~SIGNAL_CTRL_ASYNC_INPUT_PATH;
208a38a2233SWilliam Zhang 	__raw_writel(reg, bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
209a38a2233SWilliam Zhang 
210a38a2233SWilliam Zhang 	mutex_lock(&bs->bus_mutex);
211a38a2233SWilliam Zhang 	/* setup clock polarity */
212a38a2233SWilliam Zhang 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
213a38a2233SWilliam Zhang 	reg &= ~GLOBAL_CTRL_CLK_POLARITY;
214a38a2233SWilliam Zhang 	if (spi->mode & SPI_CPOL)
215a38a2233SWilliam Zhang 		reg |= GLOBAL_CTRL_CLK_POLARITY;
216a38a2233SWilliam Zhang 	__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
217a38a2233SWilliam Zhang 
218a38a2233SWilliam Zhang 	mutex_unlock(&bs->bus_mutex);
219a38a2233SWilliam Zhang }
220a38a2233SWilliam Zhang 
221a38a2233SWilliam Zhang static int bcmbca_hsspi_wait_cmd(struct bcmbca_hsspi *bs, unsigned int cs)
222a38a2233SWilliam Zhang {
223a38a2233SWilliam Zhang 	unsigned long limit;
224a38a2233SWilliam Zhang 	u32 reg = 0;
225a38a2233SWilliam Zhang 	int rc = 0;
226a38a2233SWilliam Zhang 
227a38a2233SWilliam Zhang 	if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
228a38a2233SWilliam Zhang 		if (wait_for_completion_timeout(&bs->done, HZ) == 0)
229a38a2233SWilliam Zhang 			rc = 1;
230a38a2233SWilliam Zhang 	} else {
231a38a2233SWilliam Zhang 		limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
232a38a2233SWilliam Zhang 
233a38a2233SWilliam Zhang 		while (!time_after(jiffies, limit)) {
234a38a2233SWilliam Zhang 			reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
235a38a2233SWilliam Zhang 			if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
236a38a2233SWilliam Zhang 				cpu_relax();
237a38a2233SWilliam Zhang 			else
238a38a2233SWilliam Zhang 				break;
239a38a2233SWilliam Zhang 		}
240a38a2233SWilliam Zhang 		if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
241a38a2233SWilliam Zhang 			rc = 1;
242a38a2233SWilliam Zhang 	}
243a38a2233SWilliam Zhang 
244a38a2233SWilliam Zhang 	if (rc)
245a38a2233SWilliam Zhang 		dev_err(&bs->pdev->dev, "transfer timed out!\n");
246a38a2233SWilliam Zhang 
247a38a2233SWilliam Zhang 	return rc;
248a38a2233SWilliam Zhang }
249a38a2233SWilliam Zhang 
250a38a2233SWilliam Zhang static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
251a38a2233SWilliam Zhang 								struct spi_message *msg)
252a38a2233SWilliam Zhang {
253a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
2549e264f3fSAmit Kumar Mahapatra via Alsa-devel 	unsigned int chip_select = spi_get_chipselect(spi, 0);
2552cca486cSWilliam Zhang 	u16 opcode = 0, val;
256a38a2233SWilliam Zhang 	int pending = t->len;
257a38a2233SWilliam Zhang 	int step_size = HSSPI_BUFFER_LEN;
258a38a2233SWilliam Zhang 	const u8 *tx = t->tx_buf;
259a38a2233SWilliam Zhang 	u8 *rx = t->rx_buf;
260a38a2233SWilliam Zhang 	u32 reg = 0, cs_act = 0;
261a38a2233SWilliam Zhang 
262a38a2233SWilliam Zhang 	bcmbca_hsspi_set_clk(bs, spi, t->speed_hz);
263a38a2233SWilliam Zhang 
264a38a2233SWilliam Zhang 	if (tx && rx)
265a38a2233SWilliam Zhang 		opcode = HSSPI_OP_READ_WRITE;
266a38a2233SWilliam Zhang 	else if (tx)
267a38a2233SWilliam Zhang 		opcode = HSSPI_OP_WRITE;
268a38a2233SWilliam Zhang 	else if (rx)
269a38a2233SWilliam Zhang 		opcode = HSSPI_OP_READ;
270a38a2233SWilliam Zhang 
271a38a2233SWilliam Zhang 	if (opcode != HSSPI_OP_READ)
272a38a2233SWilliam Zhang 		step_size -= HSSPI_OPCODE_LEN;
273a38a2233SWilliam Zhang 
274a38a2233SWilliam Zhang 	if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
275a38a2233SWilliam Zhang 	    (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
276a38a2233SWilliam Zhang 		opcode |= HSSPI_OP_MULTIBIT;
277a38a2233SWilliam Zhang 
278a38a2233SWilliam Zhang 		if (t->rx_nbits == SPI_NBITS_DUAL)
279a38a2233SWilliam Zhang 			reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
280a38a2233SWilliam Zhang 		if (t->tx_nbits == SPI_NBITS_DUAL)
281a38a2233SWilliam Zhang 			reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
282a38a2233SWilliam Zhang 	}
283a38a2233SWilliam Zhang 
284a38a2233SWilliam Zhang 	__raw_writel(reg | 0xff,
285a38a2233SWilliam Zhang 		     bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
286a38a2233SWilliam Zhang 
287a38a2233SWilliam Zhang 	while (pending > 0) {
288a38a2233SWilliam Zhang 		int curr_step = min_t(int, step_size, pending);
289a38a2233SWilliam Zhang 
290a38a2233SWilliam Zhang 		reinit_completion(&bs->done);
291a38a2233SWilliam Zhang 		if (tx) {
292a38a2233SWilliam Zhang 			memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
293a38a2233SWilliam Zhang 			tx += curr_step;
294a38a2233SWilliam Zhang 		}
2952cca486cSWilliam Zhang 
2962cca486cSWilliam Zhang 		*(__be16 *)(&val) = cpu_to_be16(opcode | curr_step);
2972cca486cSWilliam Zhang 		__raw_writew(val, bs->fifo);
298a38a2233SWilliam Zhang 
299a38a2233SWilliam Zhang 		/* enable interrupt */
300a38a2233SWilliam Zhang 		if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
301a38a2233SWilliam Zhang 			__raw_writel(HSSPI_PINGx_CMD_DONE(0),
302a38a2233SWilliam Zhang 			    bs->regs + HSSPI_INT_MASK_REG);
303a38a2233SWilliam Zhang 
304a38a2233SWilliam Zhang 		if (!cs_act) {
305a38a2233SWilliam Zhang 			/* must apply cs signal as close as the cmd starts */
306a38a2233SWilliam Zhang 			bcmbca_hsspi_set_cs(bs, chip_select, true);
307a38a2233SWilliam Zhang 			cs_act = 1;
308a38a2233SWilliam Zhang 		}
309a38a2233SWilliam Zhang 
310a38a2233SWilliam Zhang 		reg = chip_select << PINGPONG_CMD_SS_SHIFT |
311a38a2233SWilliam Zhang 			    chip_select << PINGPONG_CMD_PROFILE_SHIFT |
312a38a2233SWilliam Zhang 			    PINGPONG_COMMAND_START_NOW;
313a38a2233SWilliam Zhang 		__raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
314a38a2233SWilliam Zhang 
3159e264f3fSAmit Kumar Mahapatra via Alsa-devel 		if (bcmbca_hsspi_wait_cmd(bs, spi_get_chipselect(spi, 0)))
316a38a2233SWilliam Zhang 			return -ETIMEDOUT;
317a38a2233SWilliam Zhang 
318a38a2233SWilliam Zhang 		pending -= curr_step;
319a38a2233SWilliam Zhang 
320a38a2233SWilliam Zhang 		if (rx) {
321a38a2233SWilliam Zhang 			memcpy_fromio(rx, bs->fifo, curr_step);
322a38a2233SWilliam Zhang 			rx += curr_step;
323a38a2233SWilliam Zhang 		}
324a38a2233SWilliam Zhang 	}
325a38a2233SWilliam Zhang 
326a38a2233SWilliam Zhang 	return 0;
327a38a2233SWilliam Zhang }
328a38a2233SWilliam Zhang 
329a38a2233SWilliam Zhang static int bcmbca_hsspi_setup(struct spi_device *spi)
330a38a2233SWilliam Zhang {
331a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
332a38a2233SWilliam Zhang 	u32 reg;
333a38a2233SWilliam Zhang 
334a38a2233SWilliam Zhang 	reg = __raw_readl(bs->regs +
3359e264f3fSAmit Kumar Mahapatra via Alsa-devel 			  HSSPI_PROFILE_SIGNAL_CTRL_REG(spi_get_chipselect(spi, 0)));
336a38a2233SWilliam Zhang 	reg &= ~(SIGNAL_CTRL_LAUNCH_RISING | SIGNAL_CTRL_LATCH_RISING);
337a38a2233SWilliam Zhang 	if (spi->mode & SPI_CPHA)
338a38a2233SWilliam Zhang 		reg |= SIGNAL_CTRL_LAUNCH_RISING;
339a38a2233SWilliam Zhang 	else
340a38a2233SWilliam Zhang 		reg |= SIGNAL_CTRL_LATCH_RISING;
341a38a2233SWilliam Zhang 	__raw_writel(reg, bs->regs +
3429e264f3fSAmit Kumar Mahapatra via Alsa-devel 		     HSSPI_PROFILE_SIGNAL_CTRL_REG(spi_get_chipselect(spi, 0)));
343a38a2233SWilliam Zhang 
344a38a2233SWilliam Zhang 	mutex_lock(&bs->bus_mutex);
345a38a2233SWilliam Zhang 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
346a38a2233SWilliam Zhang 
347a38a2233SWilliam Zhang 	if (spi->mode & SPI_CS_HIGH)
3489e264f3fSAmit Kumar Mahapatra via Alsa-devel 		reg |= BIT(spi_get_chipselect(spi, 0));
349a38a2233SWilliam Zhang 	else
3509e264f3fSAmit Kumar Mahapatra via Alsa-devel 		reg &= ~BIT(spi_get_chipselect(spi, 0));
351a38a2233SWilliam Zhang 	__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
352a38a2233SWilliam Zhang 
353a38a2233SWilliam Zhang 	if (spi->mode & SPI_CS_HIGH)
3549e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bs->cs_polarity |= BIT(spi_get_chipselect(spi, 0));
355a38a2233SWilliam Zhang 	else
3569e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bs->cs_polarity &= ~BIT(spi_get_chipselect(spi, 0));
357a38a2233SWilliam Zhang 
358a38a2233SWilliam Zhang 	reg = __raw_readl(bs->spim_ctrl);
3599e264f3fSAmit Kumar Mahapatra via Alsa-devel 	reg &= ~BIT(spi_get_chipselect(spi, 0) + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
360a38a2233SWilliam Zhang 	if (spi->mode & SPI_CS_HIGH)
3619e264f3fSAmit Kumar Mahapatra via Alsa-devel 		reg |= BIT(spi_get_chipselect(spi, 0) + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
362a38a2233SWilliam Zhang 	__raw_writel(reg, bs->spim_ctrl);
363a38a2233SWilliam Zhang 
364a38a2233SWilliam Zhang 	mutex_unlock(&bs->bus_mutex);
365a38a2233SWilliam Zhang 
366a38a2233SWilliam Zhang 	return 0;
367a38a2233SWilliam Zhang }
368a38a2233SWilliam Zhang 
369a38a2233SWilliam Zhang static int bcmbca_hsspi_transfer_one(struct spi_master *master,
370a38a2233SWilliam Zhang 				      struct spi_message *msg)
371a38a2233SWilliam Zhang {
372a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
373a38a2233SWilliam Zhang 	struct spi_transfer *t;
374a38a2233SWilliam Zhang 	struct spi_device *spi = msg->spi;
375a38a2233SWilliam Zhang 	int status = -EINVAL;
376a38a2233SWilliam Zhang 	bool keep_cs = false;
377a38a2233SWilliam Zhang 
378a38a2233SWilliam Zhang 	mutex_lock(&bs->msg_mutex);
379a38a2233SWilliam Zhang 	list_for_each_entry(t, &msg->transfers, transfer_list) {
380a38a2233SWilliam Zhang 		status = bcmbca_hsspi_do_txrx(spi, t, msg);
381a38a2233SWilliam Zhang 		if (status)
382a38a2233SWilliam Zhang 			break;
383a38a2233SWilliam Zhang 
384a38a2233SWilliam Zhang 		spi_transfer_delay_exec(t);
385a38a2233SWilliam Zhang 
386a38a2233SWilliam Zhang 		if (t->cs_change) {
387a38a2233SWilliam Zhang 			if (list_is_last(&t->transfer_list,	&msg->transfers)) {
388a38a2233SWilliam Zhang 				keep_cs = true;
389a38a2233SWilliam Zhang 			} else {
390a38a2233SWilliam Zhang 				if (!t->cs_off)
3919e264f3fSAmit Kumar Mahapatra via Alsa-devel 					bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false);
392a38a2233SWilliam Zhang 
393a38a2233SWilliam Zhang 				spi_transfer_cs_change_delay_exec(msg, t);
394a38a2233SWilliam Zhang 
395a38a2233SWilliam Zhang 				if (!list_next_entry(t, transfer_list)->cs_off)
3969e264f3fSAmit Kumar Mahapatra via Alsa-devel 					bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), true);
397a38a2233SWilliam Zhang 			}
398a38a2233SWilliam Zhang 		} else if (!list_is_last(&t->transfer_list, &msg->transfers) &&
399a38a2233SWilliam Zhang 			   t->cs_off != list_next_entry(t, transfer_list)->cs_off) {
4009e264f3fSAmit Kumar Mahapatra via Alsa-devel 			bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), t->cs_off);
401a38a2233SWilliam Zhang 		}
402a38a2233SWilliam Zhang 
403a38a2233SWilliam Zhang 		msg->actual_length += t->len;
404a38a2233SWilliam Zhang 	}
405a38a2233SWilliam Zhang 
406a38a2233SWilliam Zhang 	mutex_unlock(&bs->msg_mutex);
407a38a2233SWilliam Zhang 
408a38a2233SWilliam Zhang 	if (status || !keep_cs)
4099e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false);
410a38a2233SWilliam Zhang 
411a38a2233SWilliam Zhang 	msg->status = status;
412a38a2233SWilliam Zhang 	spi_finalize_current_message(master);
413a38a2233SWilliam Zhang 
414a38a2233SWilliam Zhang 	return 0;
415a38a2233SWilliam Zhang }
416a38a2233SWilliam Zhang 
417a38a2233SWilliam Zhang static irqreturn_t bcmbca_hsspi_interrupt(int irq, void *dev_id)
418a38a2233SWilliam Zhang {
419a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = (struct bcmbca_hsspi *)dev_id;
420a38a2233SWilliam Zhang 
421a38a2233SWilliam Zhang 	if (__raw_readl(bs->regs + HSSPI_INT_STATUS_MASKED_REG) == 0)
422a38a2233SWilliam Zhang 		return IRQ_NONE;
423a38a2233SWilliam Zhang 
424a38a2233SWilliam Zhang 	__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
425a38a2233SWilliam Zhang 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
426a38a2233SWilliam Zhang 
427a38a2233SWilliam Zhang 	complete(&bs->done);
428a38a2233SWilliam Zhang 
429a38a2233SWilliam Zhang 	return IRQ_HANDLED;
430a38a2233SWilliam Zhang }
431a38a2233SWilliam Zhang 
432a38a2233SWilliam Zhang static int bcmbca_hsspi_probe(struct platform_device *pdev)
433a38a2233SWilliam Zhang {
434a38a2233SWilliam Zhang 	struct spi_master *master;
435a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs;
436a38a2233SWilliam Zhang 	struct resource *res_mem;
437a38a2233SWilliam Zhang 	void __iomem *spim_ctrl;
438a38a2233SWilliam Zhang 	void __iomem *regs;
439a38a2233SWilliam Zhang 	struct device *dev = &pdev->dev;
440a38a2233SWilliam Zhang 	struct clk *clk, *pll_clk = NULL;
441a38a2233SWilliam Zhang 	int irq, ret;
442a38a2233SWilliam Zhang 	u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
443a38a2233SWilliam Zhang 
444a38a2233SWilliam Zhang 	irq = platform_get_irq(pdev, 0);
445a38a2233SWilliam Zhang 	if (irq < 0)
446a38a2233SWilliam Zhang 		return irq;
447a38a2233SWilliam Zhang 
448a38a2233SWilliam Zhang 	res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsspi");
449a38a2233SWilliam Zhang 	if (!res_mem)
450a38a2233SWilliam Zhang 		return -EINVAL;
451a38a2233SWilliam Zhang 	regs = devm_ioremap_resource(dev, res_mem);
452a38a2233SWilliam Zhang 	if (IS_ERR(regs))
453a38a2233SWilliam Zhang 		return PTR_ERR(regs);
454a38a2233SWilliam Zhang 
455a38a2233SWilliam Zhang 	res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spim-ctrl");
456a38a2233SWilliam Zhang 	if (!res_mem)
457a38a2233SWilliam Zhang 		return -EINVAL;
458a38a2233SWilliam Zhang 	spim_ctrl = devm_ioremap_resource(dev, res_mem);
459a38a2233SWilliam Zhang 	if (IS_ERR(spim_ctrl))
460a38a2233SWilliam Zhang 		return PTR_ERR(spim_ctrl);
461a38a2233SWilliam Zhang 
462a38a2233SWilliam Zhang 	clk = devm_clk_get(dev, "hsspi");
463a38a2233SWilliam Zhang 	if (IS_ERR(clk))
464a38a2233SWilliam Zhang 		return PTR_ERR(clk);
465a38a2233SWilliam Zhang 
466a38a2233SWilliam Zhang 	ret = clk_prepare_enable(clk);
467a38a2233SWilliam Zhang 	if (ret)
468a38a2233SWilliam Zhang 		return ret;
469a38a2233SWilliam Zhang 
470a38a2233SWilliam Zhang 	rate = clk_get_rate(clk);
471a38a2233SWilliam Zhang 	if (!rate) {
472a38a2233SWilliam Zhang 		pll_clk = devm_clk_get(dev, "pll");
473a38a2233SWilliam Zhang 
474a38a2233SWilliam Zhang 		if (IS_ERR(pll_clk)) {
475a38a2233SWilliam Zhang 			ret = PTR_ERR(pll_clk);
476a38a2233SWilliam Zhang 			goto out_disable_clk;
477a38a2233SWilliam Zhang 		}
478a38a2233SWilliam Zhang 
479a38a2233SWilliam Zhang 		ret = clk_prepare_enable(pll_clk);
480a38a2233SWilliam Zhang 		if (ret)
481a38a2233SWilliam Zhang 			goto out_disable_clk;
482a38a2233SWilliam Zhang 
483a38a2233SWilliam Zhang 		rate = clk_get_rate(pll_clk);
484a38a2233SWilliam Zhang 		if (!rate) {
485a38a2233SWilliam Zhang 			ret = -EINVAL;
486a38a2233SWilliam Zhang 			goto out_disable_pll_clk;
487a38a2233SWilliam Zhang 		}
488a38a2233SWilliam Zhang 	}
489a38a2233SWilliam Zhang 
490a38a2233SWilliam Zhang 	master = spi_alloc_master(&pdev->dev, sizeof(*bs));
491a38a2233SWilliam Zhang 	if (!master) {
492a38a2233SWilliam Zhang 		ret = -ENOMEM;
493a38a2233SWilliam Zhang 		goto out_disable_pll_clk;
494a38a2233SWilliam Zhang 	}
495a38a2233SWilliam Zhang 
496a38a2233SWilliam Zhang 	bs = spi_master_get_devdata(master);
497a38a2233SWilliam Zhang 	bs->pdev = pdev;
498a38a2233SWilliam Zhang 	bs->clk = clk;
499a38a2233SWilliam Zhang 	bs->pll_clk = pll_clk;
500a38a2233SWilliam Zhang 	bs->regs = regs;
501a38a2233SWilliam Zhang 	bs->spim_ctrl = spim_ctrl;
502a38a2233SWilliam Zhang 	bs->speed_hz = rate;
503a38a2233SWilliam Zhang 	bs->fifo = (u8 __iomem *) (bs->regs + HSSPI_FIFO_REG(0));
504a38a2233SWilliam Zhang 	bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
505a38a2233SWilliam Zhang 
506a38a2233SWilliam Zhang 	mutex_init(&bs->bus_mutex);
507a38a2233SWilliam Zhang 	mutex_init(&bs->msg_mutex);
508a38a2233SWilliam Zhang 	init_completion(&bs->done);
509a38a2233SWilliam Zhang 
510a38a2233SWilliam Zhang 	master->dev.of_node = dev->of_node;
511a38a2233SWilliam Zhang 	if (!dev->of_node)
512a38a2233SWilliam Zhang 		master->bus_num = HSSPI_BUS_NUM;
513a38a2233SWilliam Zhang 
514a38a2233SWilliam Zhang 	of_property_read_u32(dev->of_node, "num-cs", &num_cs);
515a38a2233SWilliam Zhang 	if (num_cs > 8) {
516a38a2233SWilliam Zhang 		dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
517a38a2233SWilliam Zhang 			 num_cs);
518a38a2233SWilliam Zhang 		num_cs = HSSPI_SPI_MAX_CS;
519a38a2233SWilliam Zhang 	}
520a38a2233SWilliam Zhang 	master->num_chipselect = num_cs;
521a38a2233SWilliam Zhang 	master->setup = bcmbca_hsspi_setup;
522a38a2233SWilliam Zhang 	master->transfer_one_message = bcmbca_hsspi_transfer_one;
523a38a2233SWilliam Zhang 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
524a38a2233SWilliam Zhang 	    SPI_RX_DUAL | SPI_TX_DUAL;
525a38a2233SWilliam Zhang 	master->bits_per_word_mask = SPI_BPW_MASK(8);
526a38a2233SWilliam Zhang 	master->auto_runtime_pm = true;
527a38a2233SWilliam Zhang 
528a38a2233SWilliam Zhang 	platform_set_drvdata(pdev, master);
529a38a2233SWilliam Zhang 
530a38a2233SWilliam Zhang 	/* Initialize the hardware */
531a38a2233SWilliam Zhang 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
532a38a2233SWilliam Zhang 
533a38a2233SWilliam Zhang 	/* clean up any pending interrupts */
534a38a2233SWilliam Zhang 	__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
535a38a2233SWilliam Zhang 
536a38a2233SWilliam Zhang 	/* read out default CS polarities */
537a38a2233SWilliam Zhang 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
538a38a2233SWilliam Zhang 	bs->cs_polarity = reg & GLOBAL_CTRL_CS_POLARITY_MASK;
539a38a2233SWilliam Zhang 	__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
540a38a2233SWilliam Zhang 		     bs->regs + HSSPI_GLOBAL_CTRL_REG);
541a38a2233SWilliam Zhang 
542a38a2233SWilliam Zhang 	if (irq > 0) {
543a38a2233SWilliam Zhang 		ret = devm_request_irq(dev, irq, bcmbca_hsspi_interrupt, IRQF_SHARED,
544a38a2233SWilliam Zhang 			       pdev->name, bs);
545a38a2233SWilliam Zhang 		if (ret)
546a38a2233SWilliam Zhang 			goto out_put_master;
547a38a2233SWilliam Zhang 	}
548a38a2233SWilliam Zhang 
549a38a2233SWilliam Zhang 	pm_runtime_enable(&pdev->dev);
550a38a2233SWilliam Zhang 
5510696532eSDan Carpenter 	ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
5520696532eSDan Carpenter 	if (ret) {
553a38a2233SWilliam Zhang 		dev_err(&pdev->dev, "couldn't register sysfs group\n");
554a38a2233SWilliam Zhang 		goto out_pm_disable;
555a38a2233SWilliam Zhang 	}
556a38a2233SWilliam Zhang 
557a38a2233SWilliam Zhang 	/* register and we are done */
558a38a2233SWilliam Zhang 	ret = devm_spi_register_master(dev, master);
559a38a2233SWilliam Zhang 	if (ret)
560a38a2233SWilliam Zhang 		goto out_sysgroup_disable;
561a38a2233SWilliam Zhang 
562a38a2233SWilliam Zhang 	dev_info(dev, "Broadcom BCMBCA High Speed SPI Controller driver");
563a38a2233SWilliam Zhang 
564a38a2233SWilliam Zhang 	return 0;
565a38a2233SWilliam Zhang 
566a38a2233SWilliam Zhang out_sysgroup_disable:
567a38a2233SWilliam Zhang 	sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
568a38a2233SWilliam Zhang out_pm_disable:
569a38a2233SWilliam Zhang 	pm_runtime_disable(&pdev->dev);
570a38a2233SWilliam Zhang out_put_master:
571a38a2233SWilliam Zhang 	spi_master_put(master);
572a38a2233SWilliam Zhang out_disable_pll_clk:
573a38a2233SWilliam Zhang 	clk_disable_unprepare(pll_clk);
574a38a2233SWilliam Zhang out_disable_clk:
575a38a2233SWilliam Zhang 	clk_disable_unprepare(clk);
576a38a2233SWilliam Zhang 	return ret;
577a38a2233SWilliam Zhang }
578a38a2233SWilliam Zhang 
579f54f9b00SUwe Kleine-König static void bcmbca_hsspi_remove(struct platform_device *pdev)
580a38a2233SWilliam Zhang {
581a38a2233SWilliam Zhang 	struct spi_master *master = platform_get_drvdata(pdev);
582a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
583a38a2233SWilliam Zhang 
584a38a2233SWilliam Zhang 	/* reset the hardware and block queue progress */
585a38a2233SWilliam Zhang 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
586a38a2233SWilliam Zhang 	clk_disable_unprepare(bs->pll_clk);
587a38a2233SWilliam Zhang 	clk_disable_unprepare(bs->clk);
588a38a2233SWilliam Zhang 	sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
589a38a2233SWilliam Zhang }
590a38a2233SWilliam Zhang 
591a38a2233SWilliam Zhang #ifdef CONFIG_PM_SLEEP
592a38a2233SWilliam Zhang static int bcmbca_hsspi_suspend(struct device *dev)
593a38a2233SWilliam Zhang {
594a38a2233SWilliam Zhang 	struct spi_master *master = dev_get_drvdata(dev);
595a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
596a38a2233SWilliam Zhang 
597a38a2233SWilliam Zhang 	spi_master_suspend(master);
598a38a2233SWilliam Zhang 	clk_disable_unprepare(bs->pll_clk);
599a38a2233SWilliam Zhang 	clk_disable_unprepare(bs->clk);
600a38a2233SWilliam Zhang 
601a38a2233SWilliam Zhang 	return 0;
602a38a2233SWilliam Zhang }
603a38a2233SWilliam Zhang 
604a38a2233SWilliam Zhang static int bcmbca_hsspi_resume(struct device *dev)
605a38a2233SWilliam Zhang {
606a38a2233SWilliam Zhang 	struct spi_master *master = dev_get_drvdata(dev);
607a38a2233SWilliam Zhang 	struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
608a38a2233SWilliam Zhang 	int ret;
609a38a2233SWilliam Zhang 
610a38a2233SWilliam Zhang 	ret = clk_prepare_enable(bs->clk);
611a38a2233SWilliam Zhang 	if (ret)
612a38a2233SWilliam Zhang 		return ret;
613a38a2233SWilliam Zhang 
614a38a2233SWilliam Zhang 	if (bs->pll_clk) {
615a38a2233SWilliam Zhang 		ret = clk_prepare_enable(bs->pll_clk);
616a38a2233SWilliam Zhang 		if (ret) {
617a38a2233SWilliam Zhang 			clk_disable_unprepare(bs->clk);
618a38a2233SWilliam Zhang 			return ret;
619a38a2233SWilliam Zhang 		}
620a38a2233SWilliam Zhang 	}
621a38a2233SWilliam Zhang 
622a38a2233SWilliam Zhang 	spi_master_resume(master);
623a38a2233SWilliam Zhang 
624a38a2233SWilliam Zhang 	return 0;
625a38a2233SWilliam Zhang }
626a38a2233SWilliam Zhang #endif
627a38a2233SWilliam Zhang 
628a38a2233SWilliam Zhang static SIMPLE_DEV_PM_OPS(bcmbca_hsspi_pm_ops, bcmbca_hsspi_suspend,
629a38a2233SWilliam Zhang 			 bcmbca_hsspi_resume);
630a38a2233SWilliam Zhang 
631a38a2233SWilliam Zhang static const struct of_device_id bcmbca_hsspi_of_match[] = {
632a38a2233SWilliam Zhang 	{ .compatible = "brcm,bcmbca-hsspi-v1.1", },
633a38a2233SWilliam Zhang 	{},
634a38a2233SWilliam Zhang };
635a38a2233SWilliam Zhang 
636a38a2233SWilliam Zhang MODULE_DEVICE_TABLE(of, bcmbca_hsspi_of_match);
637a38a2233SWilliam Zhang 
638a38a2233SWilliam Zhang static struct platform_driver bcmbca_hsspi_driver = {
639a38a2233SWilliam Zhang 	.driver = {
640a38a2233SWilliam Zhang 		   .name = "bcmbca-hsspi",
641a38a2233SWilliam Zhang 		   .pm = &bcmbca_hsspi_pm_ops,
642a38a2233SWilliam Zhang 		   .of_match_table = bcmbca_hsspi_of_match,
643a38a2233SWilliam Zhang 		   },
644a38a2233SWilliam Zhang 	.probe = bcmbca_hsspi_probe,
645f54f9b00SUwe Kleine-König 	.remove_new = bcmbca_hsspi_remove,
646a38a2233SWilliam Zhang };
647a38a2233SWilliam Zhang 
648a38a2233SWilliam Zhang module_platform_driver(bcmbca_hsspi_driver);
649a38a2233SWilliam Zhang 
650a38a2233SWilliam Zhang MODULE_ALIAS("platform:bcmbca_hsspi");
651a38a2233SWilliam Zhang MODULE_DESCRIPTION("Broadcom BCMBCA High Speed SPI Controller driver");
652a38a2233SWilliam Zhang MODULE_LICENSE("GPL");
653