xref: /openbmc/linux/drivers/spi/spi-bcm63xx-hsspi.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1142168ebSJonas Gorski /*
2142168ebSJonas Gorski  * Broadcom BCM63XX High Speed SPI Controller driver
3142168ebSJonas Gorski  *
4142168ebSJonas Gorski  * Copyright 2000-2010 Broadcom Corporation
5879a879cSJonas Gorski  * Copyright 2012-2013 Jonas Gorski <jonas.gorski@gmail.com>
6142168ebSJonas Gorski  *
7142168ebSJonas Gorski  * Licensed under the GNU/GPL. See COPYING for details.
8142168ebSJonas Gorski  */
9142168ebSJonas Gorski 
10142168ebSJonas Gorski #include <linux/kernel.h>
11142168ebSJonas Gorski #include <linux/init.h>
12142168ebSJonas Gorski #include <linux/io.h>
13142168ebSJonas Gorski #include <linux/clk.h>
14142168ebSJonas Gorski #include <linux/module.h>
15142168ebSJonas Gorski #include <linux/platform_device.h>
16142168ebSJonas Gorski #include <linux/delay.h>
17142168ebSJonas Gorski #include <linux/dma-mapping.h>
18142168ebSJonas Gorski #include <linux/err.h>
19142168ebSJonas Gorski #include <linux/interrupt.h>
20142168ebSJonas Gorski #include <linux/spi/spi.h>
21142168ebSJonas Gorski #include <linux/mutex.h>
227ab24635SJonas Gorski #include <linux/of.h>
23c6182a18SWilliam Zhang #include <linux/spi/spi-mem.h>
24c6182a18SWilliam Zhang #include <linux/mtd/spi-nor.h>
250eeadddbSÁlvaro Fernández Rojas #include <linux/reset.h>
26fb8695e3SÁlvaro Fernández Rojas #include <linux/pm_runtime.h>
27142168ebSJonas Gorski 
28142168ebSJonas Gorski #define HSSPI_GLOBAL_CTRL_REG			0x0
29142168ebSJonas Gorski #define GLOBAL_CTRL_CS_POLARITY_SHIFT		0
30142168ebSJonas Gorski #define GLOBAL_CTRL_CS_POLARITY_MASK		0x000000ff
31142168ebSJonas Gorski #define GLOBAL_CTRL_PLL_CLK_CTRL_SHIFT		8
32142168ebSJonas Gorski #define GLOBAL_CTRL_PLL_CLK_CTRL_MASK		0x0000ff00
33142168ebSJonas Gorski #define GLOBAL_CTRL_CLK_GATE_SSOFF		BIT(16)
34142168ebSJonas Gorski #define GLOBAL_CTRL_CLK_POLARITY		BIT(17)
35142168ebSJonas Gorski #define GLOBAL_CTRL_MOSI_IDLE			BIT(18)
36142168ebSJonas Gorski 
37142168ebSJonas Gorski #define HSSPI_GLOBAL_EXT_TRIGGER_REG		0x4
38142168ebSJonas Gorski 
39142168ebSJonas Gorski #define HSSPI_INT_STATUS_REG			0x8
40142168ebSJonas Gorski #define HSSPI_INT_STATUS_MASKED_REG		0xc
41142168ebSJonas Gorski #define HSSPI_INT_MASK_REG			0x10
42142168ebSJonas Gorski 
43142168ebSJonas Gorski #define HSSPI_PINGx_CMD_DONE(i)			BIT((i * 8) + 0)
44142168ebSJonas Gorski #define HSSPI_PINGx_RX_OVER(i)			BIT((i * 8) + 1)
45142168ebSJonas Gorski #define HSSPI_PINGx_TX_UNDER(i)			BIT((i * 8) + 2)
46142168ebSJonas Gorski #define HSSPI_PINGx_POLL_TIMEOUT(i)		BIT((i * 8) + 3)
47142168ebSJonas Gorski #define HSSPI_PINGx_CTRL_INVAL(i)		BIT((i * 8) + 4)
48142168ebSJonas Gorski 
49142168ebSJonas Gorski #define HSSPI_INT_CLEAR_ALL			0xff001f1f
50142168ebSJonas Gorski 
51142168ebSJonas Gorski #define HSSPI_PINGPONG_COMMAND_REG(x)		(0x80 + (x) * 0x40)
52142168ebSJonas Gorski #define PINGPONG_CMD_COMMAND_MASK		0xf
53142168ebSJonas Gorski #define PINGPONG_COMMAND_NOOP			0
54142168ebSJonas Gorski #define PINGPONG_COMMAND_START_NOW		1
55142168ebSJonas Gorski #define PINGPONG_COMMAND_START_TRIGGER		2
56142168ebSJonas Gorski #define PINGPONG_COMMAND_HALT			3
57142168ebSJonas Gorski #define PINGPONG_COMMAND_FLUSH			4
58142168ebSJonas Gorski #define PINGPONG_CMD_PROFILE_SHIFT		8
59142168ebSJonas Gorski #define PINGPONG_CMD_SS_SHIFT			12
60142168ebSJonas Gorski 
61142168ebSJonas Gorski #define HSSPI_PINGPONG_STATUS_REG(x)		(0x84 + (x) * 0x40)
6250a6620dSWilliam Zhang #define HSSPI_PINGPONG_STATUS_SRC_BUSY		BIT(1)
63142168ebSJonas Gorski 
64142168ebSJonas Gorski #define HSSPI_PROFILE_CLK_CTRL_REG(x)		(0x100 + (x) * 0x20)
65142168ebSJonas Gorski #define CLK_CTRL_FREQ_CTRL_MASK			0x0000ffff
66142168ebSJonas Gorski #define CLK_CTRL_SPI_CLK_2X_SEL			BIT(14)
67142168ebSJonas Gorski #define CLK_CTRL_ACCUM_RST_ON_LOOP		BIT(15)
68142168ebSJonas Gorski 
69142168ebSJonas Gorski #define HSSPI_PROFILE_SIGNAL_CTRL_REG(x)	(0x104 + (x) * 0x20)
70142168ebSJonas Gorski #define SIGNAL_CTRL_LATCH_RISING		BIT(12)
71142168ebSJonas Gorski #define SIGNAL_CTRL_LAUNCH_RISING		BIT(13)
72142168ebSJonas Gorski #define SIGNAL_CTRL_ASYNC_INPUT_PATH		BIT(16)
73142168ebSJonas Gorski 
74142168ebSJonas Gorski #define HSSPI_PROFILE_MODE_CTRL_REG(x)		(0x108 + (x) * 0x20)
75142168ebSJonas Gorski #define MODE_CTRL_MULTIDATA_RD_STRT_SHIFT	8
76142168ebSJonas Gorski #define MODE_CTRL_MULTIDATA_WR_STRT_SHIFT	12
77142168ebSJonas Gorski #define MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT	16
78142168ebSJonas Gorski #define MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT	18
79142168ebSJonas Gorski #define MODE_CTRL_MODE_3WIRE			BIT(20)
80142168ebSJonas Gorski #define MODE_CTRL_PREPENDBYTE_CNT_SHIFT		24
81142168ebSJonas Gorski 
82142168ebSJonas Gorski #define HSSPI_FIFO_REG(x)			(0x200 + (x) * 0x200)
83142168ebSJonas Gorski 
84142168ebSJonas Gorski 
85f4d86223SJonas Gorski #define HSSPI_OP_MULTIBIT			BIT(11)
86142168ebSJonas Gorski #define HSSPI_OP_CODE_SHIFT			13
87142168ebSJonas Gorski #define HSSPI_OP_SLEEP				(0 << HSSPI_OP_CODE_SHIFT)
88142168ebSJonas Gorski #define HSSPI_OP_READ_WRITE			(1 << HSSPI_OP_CODE_SHIFT)
89142168ebSJonas Gorski #define HSSPI_OP_WRITE				(2 << HSSPI_OP_CODE_SHIFT)
90142168ebSJonas Gorski #define HSSPI_OP_READ				(3 << HSSPI_OP_CODE_SHIFT)
91142168ebSJonas Gorski #define HSSPI_OP_SETIRQ				(4 << HSSPI_OP_CODE_SHIFT)
92142168ebSJonas Gorski 
93142168ebSJonas Gorski #define HSSPI_BUFFER_LEN			512
94142168ebSJonas Gorski #define HSSPI_OPCODE_LEN			2
95142168ebSJonas Gorski 
96142168ebSJonas Gorski #define HSSPI_MAX_PREPEND_LEN			15
97142168ebSJonas Gorski 
98b7a82103SWilliam Zhang /*
99b7a82103SWilliam Zhang  * Some chip require 30MHz but other require 25MHz. Use smaller value to cover
100b7a82103SWilliam Zhang  * both cases.
101b7a82103SWilliam Zhang  */
102b7a82103SWilliam Zhang #define HSSPI_MAX_SYNC_CLOCK			25000000
103142168ebSJonas Gorski 
1047ab24635SJonas Gorski #define HSSPI_SPI_MAX_CS			8
105142168ebSJonas Gorski #define HSSPI_BUS_NUM				1 /* 0 is legacy SPI */
10650a6620dSWilliam Zhang #define HSSPI_POLL_STATUS_TIMEOUT_MS	100
10750a6620dSWilliam Zhang 
10850a6620dSWilliam Zhang #define HSSPI_WAIT_MODE_POLLING		0
10950a6620dSWilliam Zhang #define HSSPI_WAIT_MODE_INTR		1
11050a6620dSWilliam Zhang #define HSSPI_WAIT_MODE_MAX			HSSPI_WAIT_MODE_INTR
111142168ebSJonas Gorski 
112b7a82103SWilliam Zhang /*
113b7a82103SWilliam Zhang  * Default transfer mode is auto. If the msg is prependable, use the prepend
114b7a82103SWilliam Zhang  * mode.  If not, falls back to use the dummy cs workaround mode but limit the
115b7a82103SWilliam Zhang  * clock to 25MHz to make sure it works in all board design.
116b7a82103SWilliam Zhang  */
117b7a82103SWilliam Zhang #define HSSPI_XFER_MODE_AUTO		0
118b7a82103SWilliam Zhang #define HSSPI_XFER_MODE_PREPEND		1
119b7a82103SWilliam Zhang #define HSSPI_XFER_MODE_DUMMYCS		2
120b7a82103SWilliam Zhang #define HSSPI_XFER_MODE_MAX			HSSPI_XFER_MODE_DUMMYCS
121b7a82103SWilliam Zhang 
122b7a82103SWilliam Zhang #define bcm63xx_prepend_printk_on_checkfail(bs, fmt, ...)	\
123b7a82103SWilliam Zhang do {										\
124b7a82103SWilliam Zhang 	if (bs->xfer_mode == HSSPI_XFER_MODE_AUTO)				\
125b7a82103SWilliam Zhang 		dev_dbg(&bs->pdev->dev, fmt, ##__VA_ARGS__);		\
126b7a82103SWilliam Zhang 	else if (bs->xfer_mode == HSSPI_XFER_MODE_PREPEND)		\
127b7a82103SWilliam Zhang 		dev_err(&bs->pdev->dev, fmt, ##__VA_ARGS__);		\
128b7a82103SWilliam Zhang } while (0)
129b7a82103SWilliam Zhang 
130142168ebSJonas Gorski struct bcm63xx_hsspi {
131142168ebSJonas Gorski 	struct completion done;
132142168ebSJonas Gorski 	struct mutex bus_mutex;
13350a6620dSWilliam Zhang 	struct mutex msg_mutex;
134142168ebSJonas Gorski 	struct platform_device *pdev;
135142168ebSJonas Gorski 	struct clk *clk;
1360fd85869SJonas Gorski 	struct clk *pll_clk;
137142168ebSJonas Gorski 	void __iomem *regs;
138142168ebSJonas Gorski 	u8 __iomem *fifo;
139142168ebSJonas Gorski 
140142168ebSJonas Gorski 	u32 speed_hz;
141142168ebSJonas Gorski 	u8 cs_polarity;
14250a6620dSWilliam Zhang 	u32 wait_mode;
143b7a82103SWilliam Zhang 	u32 xfer_mode;
144b7a82103SWilliam Zhang 	u32 prepend_cnt;
145b7a82103SWilliam Zhang 	u8 *prepend_buf;
14650a6620dSWilliam Zhang };
14750a6620dSWilliam Zhang 
wait_mode_show(struct device * dev,struct device_attribute * attr,char * buf)14850a6620dSWilliam Zhang static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
14950a6620dSWilliam Zhang 			 char *buf)
15050a6620dSWilliam Zhang {
15150a6620dSWilliam Zhang 	struct spi_controller *ctrl = dev_get_drvdata(dev);
152*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
15350a6620dSWilliam Zhang 
15450a6620dSWilliam Zhang 	return sprintf(buf, "%d\n", bs->wait_mode);
15550a6620dSWilliam Zhang }
15650a6620dSWilliam Zhang 
wait_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)15750a6620dSWilliam Zhang static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
15850a6620dSWilliam Zhang 			  const char *buf, size_t count)
15950a6620dSWilliam Zhang {
16050a6620dSWilliam Zhang 	struct spi_controller *ctrl = dev_get_drvdata(dev);
161*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
16250a6620dSWilliam Zhang 	u32 val;
16350a6620dSWilliam Zhang 
16450a6620dSWilliam Zhang 	if (kstrtou32(buf, 10, &val))
16550a6620dSWilliam Zhang 		return -EINVAL;
16650a6620dSWilliam Zhang 
16750a6620dSWilliam Zhang 	if (val > HSSPI_WAIT_MODE_MAX) {
16850a6620dSWilliam Zhang 		dev_warn(dev, "invalid wait mode %u\n", val);
16950a6620dSWilliam Zhang 		return -EINVAL;
17050a6620dSWilliam Zhang 	}
17150a6620dSWilliam Zhang 
17250a6620dSWilliam Zhang 	mutex_lock(&bs->msg_mutex);
17350a6620dSWilliam Zhang 	bs->wait_mode = val;
17450a6620dSWilliam Zhang 	/* clear interrupt status to avoid spurious int on next transfer */
17550a6620dSWilliam Zhang 	if (val == HSSPI_WAIT_MODE_INTR)
17650a6620dSWilliam Zhang 		__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
17750a6620dSWilliam Zhang 	mutex_unlock(&bs->msg_mutex);
17850a6620dSWilliam Zhang 
17950a6620dSWilliam Zhang 	return count;
18050a6620dSWilliam Zhang }
18150a6620dSWilliam Zhang 
18250a6620dSWilliam Zhang static DEVICE_ATTR_RW(wait_mode);
18350a6620dSWilliam Zhang 
xfer_mode_show(struct device * dev,struct device_attribute * attr,char * buf)184b7a82103SWilliam Zhang static ssize_t xfer_mode_show(struct device *dev, struct device_attribute *attr,
185b7a82103SWilliam Zhang 			 char *buf)
186b7a82103SWilliam Zhang {
187b7a82103SWilliam Zhang 	struct spi_controller *ctrl = dev_get_drvdata(dev);
188*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
189b7a82103SWilliam Zhang 
190b7a82103SWilliam Zhang 	return sprintf(buf, "%d\n", bs->xfer_mode);
191b7a82103SWilliam Zhang }
192b7a82103SWilliam Zhang 
xfer_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)193b7a82103SWilliam Zhang static ssize_t xfer_mode_store(struct device *dev, struct device_attribute *attr,
194b7a82103SWilliam Zhang 			  const char *buf, size_t count)
195b7a82103SWilliam Zhang {
196b7a82103SWilliam Zhang 	struct spi_controller *ctrl = dev_get_drvdata(dev);
197*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
198b7a82103SWilliam Zhang 	u32 val;
199b7a82103SWilliam Zhang 
200b7a82103SWilliam Zhang 	if (kstrtou32(buf, 10, &val))
201b7a82103SWilliam Zhang 		return -EINVAL;
202b7a82103SWilliam Zhang 
203b7a82103SWilliam Zhang 	if (val > HSSPI_XFER_MODE_MAX) {
204b7a82103SWilliam Zhang 		dev_warn(dev, "invalid xfer mode %u\n", val);
205b7a82103SWilliam Zhang 		return -EINVAL;
206b7a82103SWilliam Zhang 	}
207b7a82103SWilliam Zhang 
208b7a82103SWilliam Zhang 	mutex_lock(&bs->msg_mutex);
209b7a82103SWilliam Zhang 	bs->xfer_mode = val;
210b7a82103SWilliam Zhang 	mutex_unlock(&bs->msg_mutex);
211b7a82103SWilliam Zhang 
212b7a82103SWilliam Zhang 	return count;
213b7a82103SWilliam Zhang }
214b7a82103SWilliam Zhang 
215b7a82103SWilliam Zhang static DEVICE_ATTR_RW(xfer_mode);
216b7a82103SWilliam Zhang 
21750a6620dSWilliam Zhang static struct attribute *bcm63xx_hsspi_attrs[] = {
21850a6620dSWilliam Zhang 	&dev_attr_wait_mode.attr,
219b7a82103SWilliam Zhang 	&dev_attr_xfer_mode.attr,
22050a6620dSWilliam Zhang 	NULL,
22150a6620dSWilliam Zhang };
22250a6620dSWilliam Zhang 
22350a6620dSWilliam Zhang static const struct attribute_group bcm63xx_hsspi_group = {
22450a6620dSWilliam Zhang 	.attrs = bcm63xx_hsspi_attrs,
225142168ebSJonas Gorski };
226142168ebSJonas Gorski 
227b7a82103SWilliam Zhang static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
228b7a82103SWilliam Zhang 				  struct spi_device *spi, int hz);
229b7a82103SWilliam Zhang 
bcm63xx_hsspi_max_message_size(struct spi_device * spi)230b7a82103SWilliam Zhang static size_t bcm63xx_hsspi_max_message_size(struct spi_device *spi)
231b7a82103SWilliam Zhang {
232b7a82103SWilliam Zhang 	return HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN;
233b7a82103SWilliam Zhang }
234b7a82103SWilliam Zhang 
bcm63xx_hsspi_wait_cmd(struct bcm63xx_hsspi * bs)235b7a82103SWilliam Zhang static int bcm63xx_hsspi_wait_cmd(struct bcm63xx_hsspi *bs)
236b7a82103SWilliam Zhang {
237b7a82103SWilliam Zhang 	unsigned long limit;
238b7a82103SWilliam Zhang 	u32 reg = 0;
239b7a82103SWilliam Zhang 	int rc = 0;
240b7a82103SWilliam Zhang 
241b7a82103SWilliam Zhang 	if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
242b7a82103SWilliam Zhang 		if (wait_for_completion_timeout(&bs->done, HZ) == 0)
243b7a82103SWilliam Zhang 			rc = 1;
244b7a82103SWilliam Zhang 	} else {
245b7a82103SWilliam Zhang 		/* polling mode checks for status busy bit */
246b7a82103SWilliam Zhang 		limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
247b7a82103SWilliam Zhang 
248b7a82103SWilliam Zhang 		while (!time_after(jiffies, limit)) {
249b7a82103SWilliam Zhang 			reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
250b7a82103SWilliam Zhang 			if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
251b7a82103SWilliam Zhang 				cpu_relax();
252b7a82103SWilliam Zhang 			else
253b7a82103SWilliam Zhang 				break;
254b7a82103SWilliam Zhang 		}
255b7a82103SWilliam Zhang 		if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
256b7a82103SWilliam Zhang 			rc = 1;
257b7a82103SWilliam Zhang 	}
258b7a82103SWilliam Zhang 
259b7a82103SWilliam Zhang 	if (rc)
260b7a82103SWilliam Zhang 		dev_err(&bs->pdev->dev, "transfer timed out!\n");
261b7a82103SWilliam Zhang 
262b7a82103SWilliam Zhang 	return rc;
263b7a82103SWilliam Zhang }
264b7a82103SWilliam Zhang 
bcm63xx_prepare_prepend_transfer(struct spi_controller * host,struct spi_message * msg,struct spi_transfer * t_prepend)265*2c40be6bSYang Yingliang static bool bcm63xx_prepare_prepend_transfer(struct spi_controller *host,
266b7a82103SWilliam Zhang 					  struct spi_message *msg,
267b7a82103SWilliam Zhang 					  struct spi_transfer *t_prepend)
268b7a82103SWilliam Zhang {
269b7a82103SWilliam Zhang 
270*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
271b7a82103SWilliam Zhang 	bool tx_only = false;
272b7a82103SWilliam Zhang 	struct spi_transfer *t;
273b7a82103SWilliam Zhang 
274b7a82103SWilliam Zhang 	/*
275b7a82103SWilliam Zhang 	 * Multiple transfers within a message may be combined into one transfer
276b7a82103SWilliam Zhang 	 * to the controller using its prepend feature. A SPI message is prependable
277b7a82103SWilliam Zhang 	 * only if the following are all true:
278b7a82103SWilliam Zhang 	 *   1. One or more half duplex write transfer in single bit mode
279b7a82103SWilliam Zhang 	 *   2. Optional full duplex read/write at the end
280b7a82103SWilliam Zhang 	 *   3. No delay and cs_change between transfers
281b7a82103SWilliam Zhang 	 */
282b7a82103SWilliam Zhang 	bs->prepend_cnt = 0;
283b7a82103SWilliam Zhang 	list_for_each_entry(t, &msg->transfers, transfer_list) {
284b7a82103SWilliam Zhang 		if ((spi_delay_to_ns(&t->delay, t) > 0) || t->cs_change) {
285b7a82103SWilliam Zhang 			bcm63xx_prepend_printk_on_checkfail(bs,
286b7a82103SWilliam Zhang 				 "Delay or cs change not supported in prepend mode!\n");
287b7a82103SWilliam Zhang 			return false;
288b7a82103SWilliam Zhang 		}
289b7a82103SWilliam Zhang 
290b7a82103SWilliam Zhang 		tx_only = false;
291b7a82103SWilliam Zhang 		if (t->tx_buf && !t->rx_buf) {
292b7a82103SWilliam Zhang 			tx_only = true;
293b7a82103SWilliam Zhang 			if (bs->prepend_cnt + t->len >
294b7a82103SWilliam Zhang 				(HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN)) {
295b7a82103SWilliam Zhang 				bcm63xx_prepend_printk_on_checkfail(bs,
296b7a82103SWilliam Zhang 					 "exceed max buf len, abort prepending transfers!\n");
297b7a82103SWilliam Zhang 				return false;
298b7a82103SWilliam Zhang 			}
299b7a82103SWilliam Zhang 
300b7a82103SWilliam Zhang 			if (t->tx_nbits > SPI_NBITS_SINGLE &&
301b7a82103SWilliam Zhang 				!list_is_last(&t->transfer_list, &msg->transfers)) {
302b7a82103SWilliam Zhang 				bcm63xx_prepend_printk_on_checkfail(bs,
303b7a82103SWilliam Zhang 					 "multi-bit prepend buf not supported!\n");
304b7a82103SWilliam Zhang 				return false;
305b7a82103SWilliam Zhang 			}
306b7a82103SWilliam Zhang 
307b7a82103SWilliam Zhang 			if (t->tx_nbits == SPI_NBITS_SINGLE) {
308b7a82103SWilliam Zhang 				memcpy(bs->prepend_buf + bs->prepend_cnt, t->tx_buf, t->len);
309b7a82103SWilliam Zhang 				bs->prepend_cnt += t->len;
310b7a82103SWilliam Zhang 			}
311b7a82103SWilliam Zhang 		} else {
312b7a82103SWilliam Zhang 			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
313b7a82103SWilliam Zhang 				bcm63xx_prepend_printk_on_checkfail(bs,
314b7a82103SWilliam Zhang 					 "rx/tx_rx transfer not supported when it is not last one!\n");
315b7a82103SWilliam Zhang 				return false;
316b7a82103SWilliam Zhang 			}
317b7a82103SWilliam Zhang 		}
318b7a82103SWilliam Zhang 
319b7a82103SWilliam Zhang 		if (list_is_last(&t->transfer_list, &msg->transfers)) {
320b7a82103SWilliam Zhang 			memcpy(t_prepend, t, sizeof(struct spi_transfer));
321b7a82103SWilliam Zhang 
322b7a82103SWilliam Zhang 			if (tx_only && t->tx_nbits == SPI_NBITS_SINGLE) {
323b7a82103SWilliam Zhang 				/*
324b7a82103SWilliam Zhang 				 * if the last one is also a single bit tx only transfer, merge
325b7a82103SWilliam Zhang 				 * all of them into one single tx transfer
326b7a82103SWilliam Zhang 				 */
327b7a82103SWilliam Zhang 				t_prepend->len = bs->prepend_cnt;
328b7a82103SWilliam Zhang 				t_prepend->tx_buf = bs->prepend_buf;
329b7a82103SWilliam Zhang 				bs->prepend_cnt = 0;
330b7a82103SWilliam Zhang 			} else {
331b7a82103SWilliam Zhang 				/*
332b7a82103SWilliam Zhang 				 * if the last one is not a tx only transfer or dual tx xfer, all
333b7a82103SWilliam Zhang 				 * the previous transfers are sent through prepend bytes and
334b7a82103SWilliam Zhang 				 * make sure it does not exceed the max prepend len
335b7a82103SWilliam Zhang 				 */
336b7a82103SWilliam Zhang 				if (bs->prepend_cnt > HSSPI_MAX_PREPEND_LEN) {
337b7a82103SWilliam Zhang 					bcm63xx_prepend_printk_on_checkfail(bs,
338b7a82103SWilliam Zhang 						"exceed max prepend len, abort prepending transfers!\n");
339b7a82103SWilliam Zhang 					return false;
340b7a82103SWilliam Zhang 				}
341b7a82103SWilliam Zhang 			}
342b7a82103SWilliam Zhang 		}
343b7a82103SWilliam Zhang 	}
344b7a82103SWilliam Zhang 
345b7a82103SWilliam Zhang 	return true;
346b7a82103SWilliam Zhang }
347b7a82103SWilliam Zhang 
bcm63xx_hsspi_do_prepend_txrx(struct spi_device * spi,struct spi_transfer * t)348b7a82103SWilliam Zhang static int bcm63xx_hsspi_do_prepend_txrx(struct spi_device *spi,
349b7a82103SWilliam Zhang 					 struct spi_transfer *t)
350b7a82103SWilliam Zhang {
351*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
3529e264f3fSAmit Kumar Mahapatra via Alsa-devel 	unsigned int chip_select = spi_get_chipselect(spi, 0);
3532cca486cSWilliam Zhang 	u16 opcode = 0, val;
354b7a82103SWilliam Zhang 	const u8 *tx = t->tx_buf;
355b7a82103SWilliam Zhang 	u8 *rx = t->rx_buf;
356b7a82103SWilliam Zhang 	u32 reg = 0;
357b7a82103SWilliam Zhang 
358b7a82103SWilliam Zhang 	/*
359b7a82103SWilliam Zhang 	 * shouldn't happen as we set the max_message_size in the probe.
360b7a82103SWilliam Zhang 	 * but check it again in case some driver does not honor the max size
361b7a82103SWilliam Zhang 	 */
362b7a82103SWilliam Zhang 	if (t->len + bs->prepend_cnt > (HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN)) {
363b7a82103SWilliam Zhang 		dev_warn(&bs->pdev->dev,
364b7a82103SWilliam Zhang 			 "Prepend message large than fifo size len %d prepend %d\n",
365b7a82103SWilliam Zhang 			 t->len, bs->prepend_cnt);
366b7a82103SWilliam Zhang 		return -EINVAL;
367b7a82103SWilliam Zhang 	}
368b7a82103SWilliam Zhang 
369b7a82103SWilliam Zhang 	bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
370b7a82103SWilliam Zhang 
371b7a82103SWilliam Zhang 	if (tx && rx)
372b7a82103SWilliam Zhang 		opcode = HSSPI_OP_READ_WRITE;
373b7a82103SWilliam Zhang 	else if (tx)
374b7a82103SWilliam Zhang 		opcode = HSSPI_OP_WRITE;
375b7a82103SWilliam Zhang 	else if (rx)
376b7a82103SWilliam Zhang 		opcode = HSSPI_OP_READ;
377b7a82103SWilliam Zhang 
378b7a82103SWilliam Zhang 	if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
379b7a82103SWilliam Zhang 	    (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
380b7a82103SWilliam Zhang 		opcode |= HSSPI_OP_MULTIBIT;
381b7a82103SWilliam Zhang 
382b7a82103SWilliam Zhang 		if (t->rx_nbits == SPI_NBITS_DUAL) {
383b7a82103SWilliam Zhang 			reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
384b7a82103SWilliam Zhang 			reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT;
385b7a82103SWilliam Zhang 		}
386b7a82103SWilliam Zhang 		if (t->tx_nbits == SPI_NBITS_DUAL) {
387b7a82103SWilliam Zhang 			reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
388b7a82103SWilliam Zhang 			reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT;
389b7a82103SWilliam Zhang 		}
390b7a82103SWilliam Zhang 	}
391b7a82103SWilliam Zhang 
392b7a82103SWilliam Zhang 	reg |= bs->prepend_cnt << MODE_CTRL_PREPENDBYTE_CNT_SHIFT;
393b7a82103SWilliam Zhang 	__raw_writel(reg | 0xff,
394b7a82103SWilliam Zhang 		     bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
395b7a82103SWilliam Zhang 
396b7a82103SWilliam Zhang 	reinit_completion(&bs->done);
397b7a82103SWilliam Zhang 	if (bs->prepend_cnt)
398b7a82103SWilliam Zhang 		memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, bs->prepend_buf,
399b7a82103SWilliam Zhang 			    bs->prepend_cnt);
400b7a82103SWilliam Zhang 	if (tx)
401b7a82103SWilliam Zhang 		memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN + bs->prepend_cnt, tx,
402b7a82103SWilliam Zhang 			    t->len);
403b7a82103SWilliam Zhang 
4042cca486cSWilliam Zhang 	*(__be16 *)(&val) = cpu_to_be16(opcode | t->len);
4052cca486cSWilliam Zhang 	__raw_writew(val, bs->fifo);
406b7a82103SWilliam Zhang 	/* enable interrupt */
407b7a82103SWilliam Zhang 	if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
408b7a82103SWilliam Zhang 		__raw_writel(HSSPI_PINGx_CMD_DONE(0), bs->regs + HSSPI_INT_MASK_REG);
409b7a82103SWilliam Zhang 
410b7a82103SWilliam Zhang 	/* start the transfer */
411b7a82103SWilliam Zhang 	reg = chip_select << PINGPONG_CMD_SS_SHIFT |
412b7a82103SWilliam Zhang 	    chip_select << PINGPONG_CMD_PROFILE_SHIFT |
413b7a82103SWilliam Zhang 	    PINGPONG_COMMAND_START_NOW;
414b7a82103SWilliam Zhang 	__raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
415b7a82103SWilliam Zhang 
416b7a82103SWilliam Zhang 	if (bcm63xx_hsspi_wait_cmd(bs))
417b7a82103SWilliam Zhang 		return -ETIMEDOUT;
418b7a82103SWilliam Zhang 
419b7a82103SWilliam Zhang 	if (rx)
420b7a82103SWilliam Zhang 		memcpy_fromio(rx, bs->fifo, t->len);
421b7a82103SWilliam Zhang 
422b7a82103SWilliam Zhang 	return 0;
423b7a82103SWilliam Zhang }
424b7a82103SWilliam Zhang 
bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi * bs,unsigned int cs,bool active)425c3c25ea7SAravind Thokala static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs,
426142168ebSJonas Gorski 				 bool active)
427142168ebSJonas Gorski {
428142168ebSJonas Gorski 	u32 reg;
429142168ebSJonas Gorski 
430142168ebSJonas Gorski 	mutex_lock(&bs->bus_mutex);
431142168ebSJonas Gorski 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
432142168ebSJonas Gorski 
433142168ebSJonas Gorski 	reg &= ~BIT(cs);
434142168ebSJonas Gorski 	if (active == !(bs->cs_polarity & BIT(cs)))
435142168ebSJonas Gorski 		reg |= BIT(cs);
436142168ebSJonas Gorski 
437142168ebSJonas Gorski 	__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
438142168ebSJonas Gorski 	mutex_unlock(&bs->bus_mutex);
439142168ebSJonas Gorski }
440142168ebSJonas Gorski 
bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi * bs,struct spi_device * spi,int hz)441142168ebSJonas Gorski static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
442142168ebSJonas Gorski 				  struct spi_device *spi, int hz)
443142168ebSJonas Gorski {
4449e264f3fSAmit Kumar Mahapatra via Alsa-devel 	unsigned int profile = spi_get_chipselect(spi, 0);
445142168ebSJonas Gorski 	u32 reg;
446142168ebSJonas Gorski 
447142168ebSJonas Gorski 	reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
448142168ebSJonas Gorski 	__raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
449142168ebSJonas Gorski 		     bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));
450142168ebSJonas Gorski 
451142168ebSJonas Gorski 	reg = __raw_readl(bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
452142168ebSJonas Gorski 	if (hz > HSSPI_MAX_SYNC_CLOCK)
453142168ebSJonas Gorski 		reg |= SIGNAL_CTRL_ASYNC_INPUT_PATH;
454142168ebSJonas Gorski 	else
455142168ebSJonas Gorski 		reg &= ~SIGNAL_CTRL_ASYNC_INPUT_PATH;
456142168ebSJonas Gorski 	__raw_writel(reg, bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
457142168ebSJonas Gorski 
458142168ebSJonas Gorski 	mutex_lock(&bs->bus_mutex);
459142168ebSJonas Gorski 	/* setup clock polarity */
460142168ebSJonas Gorski 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
461142168ebSJonas Gorski 	reg &= ~GLOBAL_CTRL_CLK_POLARITY;
462142168ebSJonas Gorski 	if (spi->mode & SPI_CPOL)
463142168ebSJonas Gorski 		reg |= GLOBAL_CTRL_CLK_POLARITY;
464142168ebSJonas Gorski 	__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
465142168ebSJonas Gorski 	mutex_unlock(&bs->bus_mutex);
466142168ebSJonas Gorski }
467142168ebSJonas Gorski 
bcm63xx_hsspi_do_txrx(struct spi_device * spi,struct spi_transfer * t)468142168ebSJonas Gorski static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
469142168ebSJonas Gorski {
470*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
4719e264f3fSAmit Kumar Mahapatra via Alsa-devel 	unsigned int chip_select = spi_get_chipselect(spi, 0);
4722cca486cSWilliam Zhang 	u16 opcode = 0, val;
473142168ebSJonas Gorski 	int pending = t->len;
474142168ebSJonas Gorski 	int step_size = HSSPI_BUFFER_LEN;
475142168ebSJonas Gorski 	const u8 *tx = t->tx_buf;
476142168ebSJonas Gorski 	u8 *rx = t->rx_buf;
477b7a82103SWilliam Zhang 	u32 reg = 0;
478142168ebSJonas Gorski 
479142168ebSJonas Gorski 	bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
480c00d5e93SWilliam Zhang 	if (!t->cs_off)
4819e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bcm63xx_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), true);
482142168ebSJonas Gorski 
483142168ebSJonas Gorski 	if (tx && rx)
484142168ebSJonas Gorski 		opcode = HSSPI_OP_READ_WRITE;
485142168ebSJonas Gorski 	else if (tx)
486142168ebSJonas Gorski 		opcode = HSSPI_OP_WRITE;
487142168ebSJonas Gorski 	else if (rx)
488142168ebSJonas Gorski 		opcode = HSSPI_OP_READ;
489142168ebSJonas Gorski 
490142168ebSJonas Gorski 	if (opcode != HSSPI_OP_READ)
491142168ebSJonas Gorski 		step_size -= HSSPI_OPCODE_LEN;
492142168ebSJonas Gorski 
493f4d86223SJonas Gorski 	if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
494811ff802SWilliam Zhang 	    (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
495f4d86223SJonas Gorski 		opcode |= HSSPI_OP_MULTIBIT;
496f4d86223SJonas Gorski 
497811ff802SWilliam Zhang 		if (t->rx_nbits == SPI_NBITS_DUAL)
498b7a82103SWilliam Zhang 			reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
499811ff802SWilliam Zhang 		if (t->tx_nbits == SPI_NBITS_DUAL)
500b7a82103SWilliam Zhang 			reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
501811ff802SWilliam Zhang 	}
502811ff802SWilliam Zhang 
503b7a82103SWilliam Zhang 	__raw_writel(reg | 0xff,
504142168ebSJonas Gorski 		     bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
505142168ebSJonas Gorski 
506142168ebSJonas Gorski 	while (pending > 0) {
507142168ebSJonas Gorski 		int curr_step = min_t(int, step_size, pending);
508142168ebSJonas Gorski 
509aa0fe826SAxel Lin 		reinit_completion(&bs->done);
510142168ebSJonas Gorski 		if (tx) {
511142168ebSJonas Gorski 			memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
512142168ebSJonas Gorski 			tx += curr_step;
513142168ebSJonas Gorski 		}
514142168ebSJonas Gorski 
5152cca486cSWilliam Zhang 		*(__be16 *)(&val) = cpu_to_be16(opcode | curr_step);
5162cca486cSWilliam Zhang 		__raw_writew(val, bs->fifo);
517142168ebSJonas Gorski 
518142168ebSJonas Gorski 		/* enable interrupt */
51950a6620dSWilliam Zhang 		if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
520142168ebSJonas Gorski 			__raw_writel(HSSPI_PINGx_CMD_DONE(0),
521142168ebSJonas Gorski 				     bs->regs + HSSPI_INT_MASK_REG);
522142168ebSJonas Gorski 
523b7a82103SWilliam Zhang 		reg =  !chip_select << PINGPONG_CMD_SS_SHIFT |
524142168ebSJonas Gorski 			    chip_select << PINGPONG_CMD_PROFILE_SHIFT |
525b7a82103SWilliam Zhang 			    PINGPONG_COMMAND_START_NOW;
526b7a82103SWilliam Zhang 		__raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
527142168ebSJonas Gorski 
528b7a82103SWilliam Zhang 		if (bcm63xx_hsspi_wait_cmd(bs))
529b7a82103SWilliam Zhang 			return -ETIMEDOUT;
530142168ebSJonas Gorski 
531142168ebSJonas Gorski 		if (rx) {
532142168ebSJonas Gorski 			memcpy_fromio(rx, bs->fifo, curr_step);
533142168ebSJonas Gorski 			rx += curr_step;
534142168ebSJonas Gorski 		}
535142168ebSJonas Gorski 
536142168ebSJonas Gorski 		pending -= curr_step;
537142168ebSJonas Gorski 	}
538142168ebSJonas Gorski 
539142168ebSJonas Gorski 	return 0;
540142168ebSJonas Gorski }
541142168ebSJonas Gorski 
bcm63xx_hsspi_setup(struct spi_device * spi)542142168ebSJonas Gorski static int bcm63xx_hsspi_setup(struct spi_device *spi)
543142168ebSJonas Gorski {
544*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
545142168ebSJonas Gorski 	u32 reg;
546142168ebSJonas Gorski 
547142168ebSJonas Gorski 	reg = __raw_readl(bs->regs +
5489e264f3fSAmit Kumar Mahapatra via Alsa-devel 			  HSSPI_PROFILE_SIGNAL_CTRL_REG(spi_get_chipselect(spi, 0)));
549142168ebSJonas Gorski 	reg &= ~(SIGNAL_CTRL_LAUNCH_RISING | SIGNAL_CTRL_LATCH_RISING);
550142168ebSJonas Gorski 	if (spi->mode & SPI_CPHA)
551142168ebSJonas Gorski 		reg |= SIGNAL_CTRL_LAUNCH_RISING;
552142168ebSJonas Gorski 	else
553142168ebSJonas Gorski 		reg |= SIGNAL_CTRL_LATCH_RISING;
554142168ebSJonas Gorski 	__raw_writel(reg, bs->regs +
5559e264f3fSAmit Kumar Mahapatra via Alsa-devel 		     HSSPI_PROFILE_SIGNAL_CTRL_REG(spi_get_chipselect(spi, 0)));
556142168ebSJonas Gorski 
557142168ebSJonas Gorski 	mutex_lock(&bs->bus_mutex);
558142168ebSJonas Gorski 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
559142168ebSJonas Gorski 
560142168ebSJonas Gorski 	/* only change actual polarities if there is no transfer */
561142168ebSJonas Gorski 	if ((reg & GLOBAL_CTRL_CS_POLARITY_MASK) == bs->cs_polarity) {
562142168ebSJonas Gorski 		if (spi->mode & SPI_CS_HIGH)
5639e264f3fSAmit Kumar Mahapatra via Alsa-devel 			reg |= BIT(spi_get_chipselect(spi, 0));
564142168ebSJonas Gorski 		else
5659e264f3fSAmit Kumar Mahapatra via Alsa-devel 			reg &= ~BIT(spi_get_chipselect(spi, 0));
566142168ebSJonas Gorski 		__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
567142168ebSJonas Gorski 	}
568142168ebSJonas Gorski 
569142168ebSJonas Gorski 	if (spi->mode & SPI_CS_HIGH)
5709e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bs->cs_polarity |= BIT(spi_get_chipselect(spi, 0));
571142168ebSJonas Gorski 	else
5729e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bs->cs_polarity &= ~BIT(spi_get_chipselect(spi, 0));
573142168ebSJonas Gorski 
574142168ebSJonas Gorski 	mutex_unlock(&bs->bus_mutex);
575142168ebSJonas Gorski 
576142168ebSJonas Gorski 	return 0;
577142168ebSJonas Gorski }
578142168ebSJonas Gorski 
bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device * spi,struct spi_message * msg)579b7a82103SWilliam Zhang static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
580142168ebSJonas Gorski 				      struct spi_message *msg)
581142168ebSJonas Gorski {
582*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
583142168ebSJonas Gorski 	int status = -EINVAL;
584142168ebSJonas Gorski 	int dummy_cs;
585c00d5e93SWilliam Zhang 	bool keep_cs = false;
586b7a82103SWilliam Zhang 	struct spi_transfer *t;
587142168ebSJonas Gorski 
588b7a82103SWilliam Zhang 	/*
589b7a82103SWilliam Zhang 	 * This controller does not support keeping CS active during idle.
590142168ebSJonas Gorski 	 * To work around this, we use the following ugly hack:
591142168ebSJonas Gorski 	 *
592142168ebSJonas Gorski 	 * a. Invert the target chip select's polarity so it will be active.
593142168ebSJonas Gorski 	 * b. Select a "dummy" chip select to use as the hardware target.
594142168ebSJonas Gorski 	 * c. Invert the dummy chip select's polarity so it will be inactive
595142168ebSJonas Gorski 	 *    during the actual transfers.
596142168ebSJonas Gorski 	 * d. Tell the hardware to send to the dummy chip select. Thanks to
597142168ebSJonas Gorski 	 *    the multiplexed nature of SPI the actual target will receive
598142168ebSJonas Gorski 	 *    the transfer and we see its response.
599142168ebSJonas Gorski 	 *
600142168ebSJonas Gorski 	 * e. At the end restore the polarities again to their default values.
601142168ebSJonas Gorski 	 */
602142168ebSJonas Gorski 
6039e264f3fSAmit Kumar Mahapatra via Alsa-devel 	dummy_cs = !spi_get_chipselect(spi, 0);
604142168ebSJonas Gorski 	bcm63xx_hsspi_set_cs(bs, dummy_cs, true);
605142168ebSJonas Gorski 
606142168ebSJonas Gorski 	list_for_each_entry(t, &msg->transfers, transfer_list) {
607b7a82103SWilliam Zhang 		/*
608b7a82103SWilliam Zhang 		 * We are here because one of reasons below:
609b7a82103SWilliam Zhang 		 * a. Message is not prependable and in default auto xfer mode. This mean
610b7a82103SWilliam Zhang 		 *    we fallback to dummy cs mode at maximum 25MHz safe clock rate.
611b7a82103SWilliam Zhang 		 * b. User set to use the dummy cs mode.
612b7a82103SWilliam Zhang 		 */
613b7a82103SWilliam Zhang 		if (bs->xfer_mode == HSSPI_XFER_MODE_AUTO) {
614b7a82103SWilliam Zhang 			if (t->speed_hz > HSSPI_MAX_SYNC_CLOCK) {
615b7a82103SWilliam Zhang 				t->speed_hz = HSSPI_MAX_SYNC_CLOCK;
616b7a82103SWilliam Zhang 				dev_warn_once(&bs->pdev->dev,
617b7a82103SWilliam Zhang 					"Force to dummy cs mode. Reduce the speed to %dHz",
618b7a82103SWilliam Zhang 					t->speed_hz);
619b7a82103SWilliam Zhang 			}
620b7a82103SWilliam Zhang 		}
621b7a82103SWilliam Zhang 
622142168ebSJonas Gorski 		status = bcm63xx_hsspi_do_txrx(spi, t);
623142168ebSJonas Gorski 		if (status)
624142168ebSJonas Gorski 			break;
625142168ebSJonas Gorski 
626142168ebSJonas Gorski 		msg->actual_length += t->len;
627142168ebSJonas Gorski 
628e74dc5c7SAlexandru Ardelean 		spi_transfer_delay_exec(t);
629142168ebSJonas Gorski 
630c00d5e93SWilliam Zhang 		/* use existing cs change logic from spi_transfer_one_message */
631c00d5e93SWilliam Zhang 		if (t->cs_change) {
632c00d5e93SWilliam Zhang 			if (list_is_last(&t->transfer_list, &msg->transfers)) {
633c00d5e93SWilliam Zhang 				keep_cs = true;
634c00d5e93SWilliam Zhang 			} else {
635c00d5e93SWilliam Zhang 				if (!t->cs_off)
6369e264f3fSAmit Kumar Mahapatra via Alsa-devel 					bcm63xx_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false);
637c00d5e93SWilliam Zhang 
638c00d5e93SWilliam Zhang 				spi_transfer_cs_change_delay_exec(msg, t);
639c00d5e93SWilliam Zhang 
640c00d5e93SWilliam Zhang 				if (!list_next_entry(t, transfer_list)->cs_off)
6419e264f3fSAmit Kumar Mahapatra via Alsa-devel 					bcm63xx_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), true);
642c00d5e93SWilliam Zhang 			}
643c00d5e93SWilliam Zhang 		} else if (!list_is_last(&t->transfer_list, &msg->transfers) &&
644c00d5e93SWilliam Zhang 			   t->cs_off != list_next_entry(t, transfer_list)->cs_off) {
6459e264f3fSAmit Kumar Mahapatra via Alsa-devel 			bcm63xx_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), t->cs_off);
646c00d5e93SWilliam Zhang 		}
647142168ebSJonas Gorski 	}
648142168ebSJonas Gorski 
649c00d5e93SWilliam Zhang 	bcm63xx_hsspi_set_cs(bs, dummy_cs, false);
650c00d5e93SWilliam Zhang 	if (status || !keep_cs)
6519e264f3fSAmit Kumar Mahapatra via Alsa-devel 		bcm63xx_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false);
652142168ebSJonas Gorski 
653b7a82103SWilliam Zhang 	return status;
654b7a82103SWilliam Zhang }
655b7a82103SWilliam Zhang 
bcm63xx_hsspi_transfer_one(struct spi_controller * host,struct spi_message * msg)656*2c40be6bSYang Yingliang static int bcm63xx_hsspi_transfer_one(struct spi_controller *host,
657b7a82103SWilliam Zhang 				      struct spi_message *msg)
658b7a82103SWilliam Zhang {
659*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
660b7a82103SWilliam Zhang 	struct spi_device *spi = msg->spi;
661b7a82103SWilliam Zhang 	int status = -EINVAL;
662b7a82103SWilliam Zhang 	bool prependable = false;
663b7a82103SWilliam Zhang 	struct spi_transfer t_prepend;
664b7a82103SWilliam Zhang 
665b7a82103SWilliam Zhang 	mutex_lock(&bs->msg_mutex);
666b7a82103SWilliam Zhang 
667b7a82103SWilliam Zhang 	if (bs->xfer_mode != HSSPI_XFER_MODE_DUMMYCS)
668*2c40be6bSYang Yingliang 		prependable = bcm63xx_prepare_prepend_transfer(host, msg, &t_prepend);
669b7a82103SWilliam Zhang 
670b7a82103SWilliam Zhang 	if (prependable) {
671b7a82103SWilliam Zhang 		status = bcm63xx_hsspi_do_prepend_txrx(spi, &t_prepend);
672b7a82103SWilliam Zhang 		msg->actual_length = (t_prepend.len + bs->prepend_cnt);
673b7a82103SWilliam Zhang 	} else {
674b7a82103SWilliam Zhang 		if (bs->xfer_mode == HSSPI_XFER_MODE_PREPEND) {
675b7a82103SWilliam Zhang 			dev_err(&bs->pdev->dev,
676b7a82103SWilliam Zhang 				"User sets prepend mode but msg not prependable! Abort transfer\n");
677b7a82103SWilliam Zhang 			status = -EINVAL;
678b7a82103SWilliam Zhang 		} else
679b7a82103SWilliam Zhang 			status = bcm63xx_hsspi_do_dummy_cs_txrx(spi, msg);
680b7a82103SWilliam Zhang 	}
681b7a82103SWilliam Zhang 
68250a6620dSWilliam Zhang 	mutex_unlock(&bs->msg_mutex);
683142168ebSJonas Gorski 	msg->status = status;
684*2c40be6bSYang Yingliang 	spi_finalize_current_message(host);
685142168ebSJonas Gorski 
686142168ebSJonas Gorski 	return 0;
687142168ebSJonas Gorski }
688142168ebSJonas Gorski 
bcm63xx_hsspi_mem_supports_op(struct spi_mem * mem,const struct spi_mem_op * op)689c6182a18SWilliam Zhang static bool bcm63xx_hsspi_mem_supports_op(struct spi_mem *mem,
690c6182a18SWilliam Zhang 			    const struct spi_mem_op *op)
691c6182a18SWilliam Zhang {
692c6182a18SWilliam Zhang 	if (!spi_mem_default_supports_op(mem, op))
693c6182a18SWilliam Zhang 		return false;
694c6182a18SWilliam Zhang 
695c6182a18SWilliam Zhang 	/* Controller doesn't support spi mem dual io mode */
696c6182a18SWilliam Zhang 	if ((op->cmd.opcode == SPINOR_OP_READ_1_2_2) ||
697c6182a18SWilliam Zhang 		(op->cmd.opcode == SPINOR_OP_READ_1_2_2_4B) ||
698c6182a18SWilliam Zhang 		(op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR) ||
699c6182a18SWilliam Zhang 		(op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR_4B))
700c6182a18SWilliam Zhang 		return false;
701c6182a18SWilliam Zhang 
702c6182a18SWilliam Zhang 	return true;
703c6182a18SWilliam Zhang }
704c6182a18SWilliam Zhang 
705c6182a18SWilliam Zhang static const struct spi_controller_mem_ops bcm63xx_hsspi_mem_ops = {
706c6182a18SWilliam Zhang 	.supports_op = bcm63xx_hsspi_mem_supports_op,
707c6182a18SWilliam Zhang };
708c6182a18SWilliam Zhang 
bcm63xx_hsspi_interrupt(int irq,void * dev_id)709142168ebSJonas Gorski static irqreturn_t bcm63xx_hsspi_interrupt(int irq, void *dev_id)
710142168ebSJonas Gorski {
711142168ebSJonas Gorski 	struct bcm63xx_hsspi *bs = (struct bcm63xx_hsspi *)dev_id;
712142168ebSJonas Gorski 
713142168ebSJonas Gorski 	if (__raw_readl(bs->regs + HSSPI_INT_STATUS_MASKED_REG) == 0)
714142168ebSJonas Gorski 		return IRQ_NONE;
715142168ebSJonas Gorski 
716142168ebSJonas Gorski 	__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
717142168ebSJonas Gorski 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
718142168ebSJonas Gorski 
719142168ebSJonas Gorski 	complete(&bs->done);
720142168ebSJonas Gorski 
721142168ebSJonas Gorski 	return IRQ_HANDLED;
722142168ebSJonas Gorski }
723142168ebSJonas Gorski 
bcm63xx_hsspi_probe(struct platform_device * pdev)724142168ebSJonas Gorski static int bcm63xx_hsspi_probe(struct platform_device *pdev)
725142168ebSJonas Gorski {
726*2c40be6bSYang Yingliang 	struct spi_controller *host;
727142168ebSJonas Gorski 	struct bcm63xx_hsspi *bs;
728142168ebSJonas Gorski 	void __iomem *regs;
729142168ebSJonas Gorski 	struct device *dev = &pdev->dev;
7300fd85869SJonas Gorski 	struct clk *clk, *pll_clk = NULL;
731142168ebSJonas Gorski 	int irq, ret;
7327ab24635SJonas Gorski 	u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
7330eeadddbSÁlvaro Fernández Rojas 	struct reset_control *reset;
734142168ebSJonas Gorski 
735142168ebSJonas Gorski 	irq = platform_get_irq(pdev, 0);
7366b8ac10eSStephen Boyd 	if (irq < 0)
737378da4a6SGustavo A. R. Silva 		return irq;
738142168ebSJonas Gorski 
739e364c8c2SYueHaibing 	regs = devm_platform_ioremap_resource(pdev, 0);
740142168ebSJonas Gorski 	if (IS_ERR(regs))
741142168ebSJonas Gorski 		return PTR_ERR(regs);
742142168ebSJonas Gorski 
743b1bdd4f8SJingoo Han 	clk = devm_clk_get(dev, "hsspi");
744142168ebSJonas Gorski 
745142168ebSJonas Gorski 	if (IS_ERR(clk))
746142168ebSJonas Gorski 		return PTR_ERR(clk);
747142168ebSJonas Gorski 
7480eeadddbSÁlvaro Fernández Rojas 	reset = devm_reset_control_get_optional_exclusive(dev, NULL);
7490eeadddbSÁlvaro Fernández Rojas 	if (IS_ERR(reset))
7500eeadddbSÁlvaro Fernández Rojas 		return PTR_ERR(reset);
7510eeadddbSÁlvaro Fernández Rojas 
7520d7412edSStefan Potyra 	ret = clk_prepare_enable(clk);
7530d7412edSStefan Potyra 	if (ret)
7540d7412edSStefan Potyra 		return ret;
7550d7412edSStefan Potyra 
7560eeadddbSÁlvaro Fernández Rojas 	ret = reset_control_reset(reset);
7570eeadddbSÁlvaro Fernández Rojas 	if (ret) {
7580eeadddbSÁlvaro Fernández Rojas 		dev_err(dev, "unable to reset device: %d\n", ret);
7590eeadddbSÁlvaro Fernández Rojas 		goto out_disable_clk;
7600eeadddbSÁlvaro Fernández Rojas 	}
7610eeadddbSÁlvaro Fernández Rojas 
762142168ebSJonas Gorski 	rate = clk_get_rate(clk);
763ff18e1efSJonas Gorski 	if (!rate) {
7640fd85869SJonas Gorski 		pll_clk = devm_clk_get(dev, "pll");
765ff18e1efSJonas Gorski 
7660d7412edSStefan Potyra 		if (IS_ERR(pll_clk)) {
7670d7412edSStefan Potyra 			ret = PTR_ERR(pll_clk);
7680d7412edSStefan Potyra 			goto out_disable_clk;
769ff18e1efSJonas Gorski 		}
770142168ebSJonas Gorski 
7710d7412edSStefan Potyra 		ret = clk_prepare_enable(pll_clk);
772dea5de1bSJonas Gorski 		if (ret)
7730d7412edSStefan Potyra 			goto out_disable_clk;
7740d7412edSStefan Potyra 
7750d7412edSStefan Potyra 		rate = clk_get_rate(pll_clk);
7760d7412edSStefan Potyra 		if (!rate) {
7770d7412edSStefan Potyra 			ret = -EINVAL;
7780fd85869SJonas Gorski 			goto out_disable_pll_clk;
7790d7412edSStefan Potyra 		}
7800d7412edSStefan Potyra 	}
781142168ebSJonas Gorski 
782*2c40be6bSYang Yingliang 	host = spi_alloc_host(&pdev->dev, sizeof(*bs));
783*2c40be6bSYang Yingliang 	if (!host) {
784142168ebSJonas Gorski 		ret = -ENOMEM;
7850fd85869SJonas Gorski 		goto out_disable_pll_clk;
786142168ebSJonas Gorski 	}
787142168ebSJonas Gorski 
788*2c40be6bSYang Yingliang 	bs = spi_controller_get_devdata(host);
789142168ebSJonas Gorski 	bs->pdev = pdev;
790142168ebSJonas Gorski 	bs->clk = clk;
7910fd85869SJonas Gorski 	bs->pll_clk = pll_clk;
792142168ebSJonas Gorski 	bs->regs = regs;
793142168ebSJonas Gorski 	bs->speed_hz = rate;
794142168ebSJonas Gorski 	bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
79550a6620dSWilliam Zhang 	bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
796b7a82103SWilliam Zhang 	bs->prepend_buf = devm_kzalloc(dev, HSSPI_BUFFER_LEN, GFP_KERNEL);
797b7a82103SWilliam Zhang 	if (!bs->prepend_buf) {
798b7a82103SWilliam Zhang 		ret = -ENOMEM;
799*2c40be6bSYang Yingliang 		goto out_put_host;
800b7a82103SWilliam Zhang 	}
801142168ebSJonas Gorski 
802142168ebSJonas Gorski 	mutex_init(&bs->bus_mutex);
80350a6620dSWilliam Zhang 	mutex_init(&bs->msg_mutex);
804aa0fe826SAxel Lin 	init_completion(&bs->done);
805142168ebSJonas Gorski 
806*2c40be6bSYang Yingliang 	host->mem_ops = &bcm63xx_hsspi_mem_ops;
807*2c40be6bSYang Yingliang 	host->dev.of_node = dev->of_node;
8087ab24635SJonas Gorski 	if (!dev->of_node)
809*2c40be6bSYang Yingliang 		host->bus_num = HSSPI_BUS_NUM;
8107ab24635SJonas Gorski 
8117ab24635SJonas Gorski 	of_property_read_u32(dev->of_node, "num-cs", &num_cs);
8127ab24635SJonas Gorski 	if (num_cs > 8) {
8137ab24635SJonas Gorski 		dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
8147ab24635SJonas Gorski 			 num_cs);
8157ab24635SJonas Gorski 		num_cs = HSSPI_SPI_MAX_CS;
8167ab24635SJonas Gorski 	}
817*2c40be6bSYang Yingliang 	host->num_chipselect = num_cs;
818*2c40be6bSYang Yingliang 	host->setup = bcm63xx_hsspi_setup;
819*2c40be6bSYang Yingliang 	host->transfer_one_message = bcm63xx_hsspi_transfer_one;
820*2c40be6bSYang Yingliang 	host->max_transfer_size = bcm63xx_hsspi_max_message_size;
821*2c40be6bSYang Yingliang 	host->max_message_size = bcm63xx_hsspi_max_message_size;
822b7a82103SWilliam Zhang 
823*2c40be6bSYang Yingliang 	host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
824f4d86223SJonas Gorski 			    SPI_RX_DUAL | SPI_TX_DUAL;
825*2c40be6bSYang Yingliang 	host->bits_per_word_mask = SPI_BPW_MASK(8);
826*2c40be6bSYang Yingliang 	host->auto_runtime_pm = true;
827142168ebSJonas Gorski 
828*2c40be6bSYang Yingliang 	platform_set_drvdata(pdev, host);
829142168ebSJonas Gorski 
830142168ebSJonas Gorski 	/* Initialize the hardware */
831142168ebSJonas Gorski 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
832142168ebSJonas Gorski 
833142168ebSJonas Gorski 	/* clean up any pending interrupts */
834142168ebSJonas Gorski 	__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
835142168ebSJonas Gorski 
836142168ebSJonas Gorski 	/* read out default CS polarities */
837142168ebSJonas Gorski 	reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
838142168ebSJonas Gorski 	bs->cs_polarity = reg & GLOBAL_CTRL_CS_POLARITY_MASK;
839142168ebSJonas Gorski 	__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
840142168ebSJonas Gorski 		     bs->regs + HSSPI_GLOBAL_CTRL_REG);
841142168ebSJonas Gorski 
84250a6620dSWilliam Zhang 	if (irq > 0) {
843142168ebSJonas Gorski 		ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
844142168ebSJonas Gorski 				       pdev->name, bs);
845142168ebSJonas Gorski 
846142168ebSJonas Gorski 		if (ret)
847*2c40be6bSYang Yingliang 			goto out_put_host;
84850a6620dSWilliam Zhang 	}
849142168ebSJonas Gorski 
850fb8695e3SÁlvaro Fernández Rojas 	pm_runtime_enable(&pdev->dev);
851fb8695e3SÁlvaro Fernández Rojas 
85297b7cea0SDan Carpenter 	ret = sysfs_create_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
85397b7cea0SDan Carpenter 	if (ret) {
85450a6620dSWilliam Zhang 		dev_err(&pdev->dev, "couldn't register sysfs group\n");
85550a6620dSWilliam Zhang 		goto out_pm_disable;
85650a6620dSWilliam Zhang 	}
85750a6620dSWilliam Zhang 
858142168ebSJonas Gorski 	/* register and we are done */
859*2c40be6bSYang Yingliang 	ret = devm_spi_register_controller(dev, host);
860142168ebSJonas Gorski 	if (ret)
86150a6620dSWilliam Zhang 		goto out_sysgroup_disable;
86250a6620dSWilliam Zhang 
86350a6620dSWilliam Zhang 	dev_info(dev, "Broadcom 63XX High Speed SPI Controller driver");
864142168ebSJonas Gorski 
865142168ebSJonas Gorski 	return 0;
866142168ebSJonas Gorski 
86750a6620dSWilliam Zhang out_sysgroup_disable:
86850a6620dSWilliam Zhang 	sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
869fb8695e3SÁlvaro Fernández Rojas out_pm_disable:
870fb8695e3SÁlvaro Fernández Rojas 	pm_runtime_disable(&pdev->dev);
871*2c40be6bSYang Yingliang out_put_host:
872*2c40be6bSYang Yingliang 	spi_controller_put(host);
8730fd85869SJonas Gorski out_disable_pll_clk:
8740fd85869SJonas Gorski 	clk_disable_unprepare(pll_clk);
875142168ebSJonas Gorski out_disable_clk:
876142168ebSJonas Gorski 	clk_disable_unprepare(clk);
877142168ebSJonas Gorski 	return ret;
878142168ebSJonas Gorski }
879142168ebSJonas Gorski 
880142168ebSJonas Gorski 
bcm63xx_hsspi_remove(struct platform_device * pdev)88104cd5f3fSUwe Kleine-König static void bcm63xx_hsspi_remove(struct platform_device *pdev)
882142168ebSJonas Gorski {
883*2c40be6bSYang Yingliang 	struct spi_controller *host = platform_get_drvdata(pdev);
884*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
885142168ebSJonas Gorski 
886142168ebSJonas Gorski 	/* reset the hardware and block queue progress */
887142168ebSJonas Gorski 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
8880fd85869SJonas Gorski 	clk_disable_unprepare(bs->pll_clk);
889142168ebSJonas Gorski 	clk_disable_unprepare(bs->clk);
89050a6620dSWilliam Zhang 	sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
891142168ebSJonas Gorski }
892142168ebSJonas Gorski 
893937ebf9cSJonas Gorski #ifdef CONFIG_PM_SLEEP
bcm63xx_hsspi_suspend(struct device * dev)894142168ebSJonas Gorski static int bcm63xx_hsspi_suspend(struct device *dev)
895142168ebSJonas Gorski {
896*2c40be6bSYang Yingliang 	struct spi_controller *host = dev_get_drvdata(dev);
897*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
898142168ebSJonas Gorski 
899*2c40be6bSYang Yingliang 	spi_controller_suspend(host);
9000fd85869SJonas Gorski 	clk_disable_unprepare(bs->pll_clk);
901937ebf9cSJonas Gorski 	clk_disable_unprepare(bs->clk);
902142168ebSJonas Gorski 
903142168ebSJonas Gorski 	return 0;
904142168ebSJonas Gorski }
905142168ebSJonas Gorski 
bcm63xx_hsspi_resume(struct device * dev)906142168ebSJonas Gorski static int bcm63xx_hsspi_resume(struct device *dev)
907142168ebSJonas Gorski {
908*2c40be6bSYang Yingliang 	struct spi_controller *host = dev_get_drvdata(dev);
909*2c40be6bSYang Yingliang 	struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
910937ebf9cSJonas Gorski 	int ret;
911142168ebSJonas Gorski 
912937ebf9cSJonas Gorski 	ret = clk_prepare_enable(bs->clk);
913937ebf9cSJonas Gorski 	if (ret)
914937ebf9cSJonas Gorski 		return ret;
915937ebf9cSJonas Gorski 
9160fd85869SJonas Gorski 	if (bs->pll_clk) {
9170fd85869SJonas Gorski 		ret = clk_prepare_enable(bs->pll_clk);
9189bb9ef2bSQinglang Miao 		if (ret) {
9199bb9ef2bSQinglang Miao 			clk_disable_unprepare(bs->clk);
9200fd85869SJonas Gorski 			return ret;
9210fd85869SJonas Gorski 		}
9229bb9ef2bSQinglang Miao 	}
9230fd85869SJonas Gorski 
924*2c40be6bSYang Yingliang 	spi_controller_resume(host);
925142168ebSJonas Gorski 
926142168ebSJonas Gorski 	return 0;
927142168ebSJonas Gorski }
928142168ebSJonas Gorski #endif
929142168ebSJonas Gorski 
9301480916eSJingoo Han static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
9311480916eSJingoo Han 			 bcm63xx_hsspi_resume);
932142168ebSJonas Gorski 
9337ab24635SJonas Gorski static const struct of_device_id bcm63xx_hsspi_of_match[] = {
9347ab24635SJonas Gorski 	{ .compatible = "brcm,bcm6328-hsspi", },
93599d7428aSWilliam Zhang 	{ .compatible = "brcm,bcmbca-hsspi-v1.0", },
9367ab24635SJonas Gorski 	{ },
9377ab24635SJonas Gorski };
9380b85a842SAndres Galacho MODULE_DEVICE_TABLE(of, bcm63xx_hsspi_of_match);
9397ab24635SJonas Gorski 
940142168ebSJonas Gorski static struct platform_driver bcm63xx_hsspi_driver = {
941142168ebSJonas Gorski 	.driver = {
942142168ebSJonas Gorski 		.name	= "bcm63xx-hsspi",
943937ebf9cSJonas Gorski 		.pm	= &bcm63xx_hsspi_pm_ops,
9447ab24635SJonas Gorski 		.of_match_table = bcm63xx_hsspi_of_match,
945142168ebSJonas Gorski 	},
946142168ebSJonas Gorski 	.probe		= bcm63xx_hsspi_probe,
94704cd5f3fSUwe Kleine-König 	.remove_new	= bcm63xx_hsspi_remove,
948142168ebSJonas Gorski };
949142168ebSJonas Gorski 
950142168ebSJonas Gorski module_platform_driver(bcm63xx_hsspi_driver);
951142168ebSJonas Gorski 
952142168ebSJonas Gorski MODULE_ALIAS("platform:bcm63xx_hsspi");
953142168ebSJonas Gorski MODULE_DESCRIPTION("Broadcom BCM63xx High Speed SPI Controller driver");
954142168ebSJonas Gorski MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
955142168ebSJonas Gorski MODULE_LICENSE("GPL");
956