xref: /openbmc/linux/drivers/spi/spi-meson-spifc.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1891100dfSNeil Armstrong // SPDX-License-Identifier: GPL-2.0+
2891100dfSNeil Armstrong //
3891100dfSNeil Armstrong // Driver for Amlogic Meson SPI flash controller (SPIFC)
4891100dfSNeil Armstrong //
5891100dfSNeil Armstrong // Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
6891100dfSNeil Armstrong //
7c3e4bc54SBeniamino Galvani 
8c3e4bc54SBeniamino Galvani #include <linux/clk.h>
9c3e4bc54SBeniamino Galvani #include <linux/delay.h>
10c3e4bc54SBeniamino Galvani #include <linux/device.h>
11c3e4bc54SBeniamino Galvani #include <linux/io.h>
12c3e4bc54SBeniamino Galvani #include <linux/kernel.h>
13c3e4bc54SBeniamino Galvani #include <linux/module.h>
14c3e4bc54SBeniamino Galvani #include <linux/of.h>
15c3e4bc54SBeniamino Galvani #include <linux/platform_device.h>
16c3e4bc54SBeniamino Galvani #include <linux/pm_runtime.h>
17c3e4bc54SBeniamino Galvani #include <linux/regmap.h>
18c3e4bc54SBeniamino Galvani #include <linux/spi/spi.h>
19c3e4bc54SBeniamino Galvani #include <linux/types.h>
20c3e4bc54SBeniamino Galvani 
21c3e4bc54SBeniamino Galvani /* register map */
22c3e4bc54SBeniamino Galvani #define REG_CMD			0x00
23c3e4bc54SBeniamino Galvani #define REG_ADDR		0x04
24c3e4bc54SBeniamino Galvani #define REG_CTRL		0x08
25c3e4bc54SBeniamino Galvani #define REG_CTRL1		0x0c
26c3e4bc54SBeniamino Galvani #define REG_STATUS		0x10
27c3e4bc54SBeniamino Galvani #define REG_CTRL2		0x14
28c3e4bc54SBeniamino Galvani #define REG_CLOCK		0x18
29c3e4bc54SBeniamino Galvani #define REG_USER		0x1c
30c3e4bc54SBeniamino Galvani #define REG_USER1		0x20
31c3e4bc54SBeniamino Galvani #define REG_USER2		0x24
32c3e4bc54SBeniamino Galvani #define REG_USER3		0x28
33c3e4bc54SBeniamino Galvani #define REG_USER4		0x2c
34c3e4bc54SBeniamino Galvani #define REG_SLAVE		0x30
35c3e4bc54SBeniamino Galvani #define REG_SLAVE1		0x34
36c3e4bc54SBeniamino Galvani #define REG_SLAVE2		0x38
37c3e4bc54SBeniamino Galvani #define REG_SLAVE3		0x3c
38c3e4bc54SBeniamino Galvani #define REG_C0			0x40
39c3e4bc54SBeniamino Galvani #define REG_B8			0x60
40c3e4bc54SBeniamino Galvani #define REG_MAX			0x7c
41c3e4bc54SBeniamino Galvani 
42c3e4bc54SBeniamino Galvani /* register fields */
43c3e4bc54SBeniamino Galvani #define CMD_USER		BIT(18)
44c3e4bc54SBeniamino Galvani #define CTRL_ENABLE_AHB		BIT(17)
45c3e4bc54SBeniamino Galvani #define CLOCK_SOURCE		BIT(31)
46c3e4bc54SBeniamino Galvani #define CLOCK_DIV_SHIFT		12
47c3e4bc54SBeniamino Galvani #define CLOCK_DIV_MASK		(0x3f << CLOCK_DIV_SHIFT)
48c3e4bc54SBeniamino Galvani #define CLOCK_CNT_HIGH_SHIFT	6
49c3e4bc54SBeniamino Galvani #define CLOCK_CNT_HIGH_MASK	(0x3f << CLOCK_CNT_HIGH_SHIFT)
50c3e4bc54SBeniamino Galvani #define CLOCK_CNT_LOW_SHIFT	0
51c3e4bc54SBeniamino Galvani #define CLOCK_CNT_LOW_MASK	(0x3f << CLOCK_CNT_LOW_SHIFT)
52c3e4bc54SBeniamino Galvani #define USER_DIN_EN_MS		BIT(0)
53c3e4bc54SBeniamino Galvani #define USER_CMP_MODE		BIT(2)
54c3e4bc54SBeniamino Galvani #define USER_UC_DOUT_SEL	BIT(27)
55c3e4bc54SBeniamino Galvani #define USER_UC_DIN_SEL		BIT(28)
56c3e4bc54SBeniamino Galvani #define USER_UC_MASK		((BIT(5) - 1) << 27)
57c3e4bc54SBeniamino Galvani #define USER1_BN_UC_DOUT_SHIFT	17
58c3e4bc54SBeniamino Galvani #define USER1_BN_UC_DOUT_MASK	(0xff << 16)
59c3e4bc54SBeniamino Galvani #define USER1_BN_UC_DIN_SHIFT	8
60c3e4bc54SBeniamino Galvani #define USER1_BN_UC_DIN_MASK	(0xff << 8)
61c3e4bc54SBeniamino Galvani #define USER4_CS_ACT		BIT(30)
62c3e4bc54SBeniamino Galvani #define SLAVE_TRST_DONE		BIT(4)
63c3e4bc54SBeniamino Galvani #define SLAVE_OP_MODE		BIT(30)
64c3e4bc54SBeniamino Galvani #define SLAVE_SW_RST		BIT(31)
65c3e4bc54SBeniamino Galvani 
66c3e4bc54SBeniamino Galvani #define SPIFC_BUFFER_SIZE	64
67c3e4bc54SBeniamino Galvani 
68c3e4bc54SBeniamino Galvani /**
69c3e4bc54SBeniamino Galvani  * struct meson_spifc
70c3e4bc54SBeniamino Galvani  * @master:	the SPI master
71c3e4bc54SBeniamino Galvani  * @regmap:	regmap for device registers
72c3e4bc54SBeniamino Galvani  * @clk:	input clock of the built-in baud rate generator
7378a7f0c0SLee Jones  * @dev:	the device structure
74c3e4bc54SBeniamino Galvani  */
75c3e4bc54SBeniamino Galvani struct meson_spifc {
76c3e4bc54SBeniamino Galvani 	struct spi_master *master;
77c3e4bc54SBeniamino Galvani 	struct regmap *regmap;
78c3e4bc54SBeniamino Galvani 	struct clk *clk;
79c3e4bc54SBeniamino Galvani 	struct device *dev;
80c3e4bc54SBeniamino Galvani };
81c3e4bc54SBeniamino Galvani 
829caf5067SKrzysztof Kozlowski static const struct regmap_config spifc_regmap_config = {
83c3e4bc54SBeniamino Galvani 	.reg_bits = 32,
84c3e4bc54SBeniamino Galvani 	.val_bits = 32,
85c3e4bc54SBeniamino Galvani 	.reg_stride = 4,
86c3e4bc54SBeniamino Galvani 	.max_register = REG_MAX,
87c3e4bc54SBeniamino Galvani };
88c3e4bc54SBeniamino Galvani 
89c3e4bc54SBeniamino Galvani /**
90c3e4bc54SBeniamino Galvani  * meson_spifc_wait_ready() - wait for the current operation to terminate
91c3e4bc54SBeniamino Galvani  * @spifc:	the Meson SPI device
92c3e4bc54SBeniamino Galvani  * Return:	0 on success, a negative value on error
93c3e4bc54SBeniamino Galvani  */
meson_spifc_wait_ready(struct meson_spifc * spifc)94c3e4bc54SBeniamino Galvani static int meson_spifc_wait_ready(struct meson_spifc *spifc)
95c3e4bc54SBeniamino Galvani {
96c3e4bc54SBeniamino Galvani 	unsigned long deadline = jiffies + msecs_to_jiffies(5);
97c3e4bc54SBeniamino Galvani 	u32 data;
98c3e4bc54SBeniamino Galvani 
99c3e4bc54SBeniamino Galvani 	do {
100c3e4bc54SBeniamino Galvani 		regmap_read(spifc->regmap, REG_SLAVE, &data);
101c3e4bc54SBeniamino Galvani 		if (data & SLAVE_TRST_DONE)
102c3e4bc54SBeniamino Galvani 			return 0;
103c3e4bc54SBeniamino Galvani 		cond_resched();
104c3e4bc54SBeniamino Galvani 	} while (!time_after(jiffies, deadline));
105c3e4bc54SBeniamino Galvani 
106c3e4bc54SBeniamino Galvani 	return -ETIMEDOUT;
107c3e4bc54SBeniamino Galvani }
108c3e4bc54SBeniamino Galvani 
109c3e4bc54SBeniamino Galvani /**
110c3e4bc54SBeniamino Galvani  * meson_spifc_drain_buffer() - copy data from device buffer to memory
111c3e4bc54SBeniamino Galvani  * @spifc:	the Meson SPI device
112c3e4bc54SBeniamino Galvani  * @buf:	the destination buffer
113c3e4bc54SBeniamino Galvani  * @len:	number of bytes to copy
114c3e4bc54SBeniamino Galvani  */
meson_spifc_drain_buffer(struct meson_spifc * spifc,u8 * buf,int len)115c3e4bc54SBeniamino Galvani static void meson_spifc_drain_buffer(struct meson_spifc *spifc, u8 *buf,
116c3e4bc54SBeniamino Galvani 				     int len)
117c3e4bc54SBeniamino Galvani {
118c3e4bc54SBeniamino Galvani 	u32 data;
119c3e4bc54SBeniamino Galvani 	int i = 0;
120c3e4bc54SBeniamino Galvani 
121c3e4bc54SBeniamino Galvani 	while (i < len) {
122c3e4bc54SBeniamino Galvani 		regmap_read(spifc->regmap, REG_C0 + i, &data);
123c3e4bc54SBeniamino Galvani 
124c3e4bc54SBeniamino Galvani 		if (len - i >= 4) {
125c3e4bc54SBeniamino Galvani 			*((u32 *)buf) = data;
126c3e4bc54SBeniamino Galvani 			buf += 4;
127c3e4bc54SBeniamino Galvani 		} else {
128c3e4bc54SBeniamino Galvani 			memcpy(buf, &data, len - i);
129c3e4bc54SBeniamino Galvani 			break;
130c3e4bc54SBeniamino Galvani 		}
131c3e4bc54SBeniamino Galvani 		i += 4;
132c3e4bc54SBeniamino Galvani 	}
133c3e4bc54SBeniamino Galvani }
134c3e4bc54SBeniamino Galvani 
135c3e4bc54SBeniamino Galvani /**
136c3e4bc54SBeniamino Galvani  * meson_spifc_fill_buffer() - copy data from memory to device buffer
137c3e4bc54SBeniamino Galvani  * @spifc:	the Meson SPI device
138c3e4bc54SBeniamino Galvani  * @buf:	the source buffer
139c3e4bc54SBeniamino Galvani  * @len:	number of bytes to copy
140c3e4bc54SBeniamino Galvani  */
meson_spifc_fill_buffer(struct meson_spifc * spifc,const u8 * buf,int len)141c3e4bc54SBeniamino Galvani static void meson_spifc_fill_buffer(struct meson_spifc *spifc, const u8 *buf,
142c3e4bc54SBeniamino Galvani 				    int len)
143c3e4bc54SBeniamino Galvani {
144c3e4bc54SBeniamino Galvani 	u32 data;
145c3e4bc54SBeniamino Galvani 	int i = 0;
146c3e4bc54SBeniamino Galvani 
147c3e4bc54SBeniamino Galvani 	while (i < len) {
148c3e4bc54SBeniamino Galvani 		if (len - i >= 4)
149c3e4bc54SBeniamino Galvani 			data = *(u32 *)buf;
150c3e4bc54SBeniamino Galvani 		else
151c3e4bc54SBeniamino Galvani 			memcpy(&data, buf, len - i);
152c3e4bc54SBeniamino Galvani 
153c3e4bc54SBeniamino Galvani 		regmap_write(spifc->regmap, REG_C0 + i, data);
154c3e4bc54SBeniamino Galvani 
155c3e4bc54SBeniamino Galvani 		buf += 4;
156c3e4bc54SBeniamino Galvani 		i += 4;
157c3e4bc54SBeniamino Galvani 	}
158c3e4bc54SBeniamino Galvani }
159c3e4bc54SBeniamino Galvani 
160c3e4bc54SBeniamino Galvani /**
161c3e4bc54SBeniamino Galvani  * meson_spifc_setup_speed() - program the clock divider
162c3e4bc54SBeniamino Galvani  * @spifc:	the Meson SPI device
163c3e4bc54SBeniamino Galvani  * @speed:	desired speed in Hz
164c3e4bc54SBeniamino Galvani  */
meson_spifc_setup_speed(struct meson_spifc * spifc,u32 speed)165008c2a2eSkbuild test robot static void meson_spifc_setup_speed(struct meson_spifc *spifc, u32 speed)
166c3e4bc54SBeniamino Galvani {
167c3e4bc54SBeniamino Galvani 	unsigned long parent, value;
168c3e4bc54SBeniamino Galvani 	int n;
169c3e4bc54SBeniamino Galvani 
170c3e4bc54SBeniamino Galvani 	parent = clk_get_rate(spifc->clk);
171c3e4bc54SBeniamino Galvani 	n = max_t(int, parent / speed - 1, 1);
172c3e4bc54SBeniamino Galvani 
173c3e4bc54SBeniamino Galvani 	dev_dbg(spifc->dev, "parent %lu, speed %u, n %d\n", parent,
174c3e4bc54SBeniamino Galvani 		speed, n);
175c3e4bc54SBeniamino Galvani 
176c3e4bc54SBeniamino Galvani 	value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK;
177c3e4bc54SBeniamino Galvani 	value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK;
178c3e4bc54SBeniamino Galvani 	value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) &
179c3e4bc54SBeniamino Galvani 		CLOCK_CNT_HIGH_MASK;
180c3e4bc54SBeniamino Galvani 
181c3e4bc54SBeniamino Galvani 	regmap_write(spifc->regmap, REG_CLOCK, value);
182c3e4bc54SBeniamino Galvani }
183c3e4bc54SBeniamino Galvani 
184c3e4bc54SBeniamino Galvani /**
185c3e4bc54SBeniamino Galvani  * meson_spifc_txrx() - transfer a chunk of data
186c3e4bc54SBeniamino Galvani  * @spifc:	the Meson SPI device
187c3e4bc54SBeniamino Galvani  * @xfer:	the current SPI transfer
188c3e4bc54SBeniamino Galvani  * @offset:	offset of the data to transfer
189c3e4bc54SBeniamino Galvani  * @len:	length of the data to transfer
190c3e4bc54SBeniamino Galvani  * @last_xfer:	whether this is the last transfer of the message
191c3e4bc54SBeniamino Galvani  * @last_chunk:	whether this is the last chunk of the transfer
192c3e4bc54SBeniamino Galvani  * Return:	0 on success, a negative value on error
193c3e4bc54SBeniamino Galvani  */
meson_spifc_txrx(struct meson_spifc * spifc,struct spi_transfer * xfer,int offset,int len,bool last_xfer,bool last_chunk)194c3e4bc54SBeniamino Galvani static int meson_spifc_txrx(struct meson_spifc *spifc,
195c3e4bc54SBeniamino Galvani 			    struct spi_transfer *xfer,
196c3e4bc54SBeniamino Galvani 			    int offset, int len, bool last_xfer,
197c3e4bc54SBeniamino Galvani 			    bool last_chunk)
198c3e4bc54SBeniamino Galvani {
199c3e4bc54SBeniamino Galvani 	bool keep_cs = true;
200c3e4bc54SBeniamino Galvani 	int ret;
201c3e4bc54SBeniamino Galvani 
202c3e4bc54SBeniamino Galvani 	if (xfer->tx_buf)
203c3e4bc54SBeniamino Galvani 		meson_spifc_fill_buffer(spifc, xfer->tx_buf + offset, len);
204c3e4bc54SBeniamino Galvani 
205c3e4bc54SBeniamino Galvani 	/* enable DOUT stage */
206c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK,
207c3e4bc54SBeniamino Galvani 			   USER_UC_DOUT_SEL);
208c3e4bc54SBeniamino Galvani 	regmap_write(spifc->regmap, REG_USER1,
209c3e4bc54SBeniamino Galvani 		     (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT);
210c3e4bc54SBeniamino Galvani 
211c3e4bc54SBeniamino Galvani 	/* enable data input during DOUT */
212c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS,
213c3e4bc54SBeniamino Galvani 			   USER_DIN_EN_MS);
214c3e4bc54SBeniamino Galvani 
215c3e4bc54SBeniamino Galvani 	if (last_chunk) {
216c3e4bc54SBeniamino Galvani 		if (last_xfer)
217c3e4bc54SBeniamino Galvani 			keep_cs = xfer->cs_change;
218c3e4bc54SBeniamino Galvani 		else
219c3e4bc54SBeniamino Galvani 			keep_cs = !xfer->cs_change;
220c3e4bc54SBeniamino Galvani 	}
221c3e4bc54SBeniamino Galvani 
222c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT,
223c3e4bc54SBeniamino Galvani 			   keep_cs ? USER4_CS_ACT : 0);
224c3e4bc54SBeniamino Galvani 
225c3e4bc54SBeniamino Galvani 	/* clear transition done bit */
226c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0);
227c3e4bc54SBeniamino Galvani 	/* start transfer */
228c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER);
229c3e4bc54SBeniamino Galvani 
230c3e4bc54SBeniamino Galvani 	ret = meson_spifc_wait_ready(spifc);
231c3e4bc54SBeniamino Galvani 
232c3e4bc54SBeniamino Galvani 	if (!ret && xfer->rx_buf)
233c3e4bc54SBeniamino Galvani 		meson_spifc_drain_buffer(spifc, xfer->rx_buf + offset, len);
234c3e4bc54SBeniamino Galvani 
235c3e4bc54SBeniamino Galvani 	return ret;
236c3e4bc54SBeniamino Galvani }
237c3e4bc54SBeniamino Galvani 
238c3e4bc54SBeniamino Galvani /**
239c3e4bc54SBeniamino Galvani  * meson_spifc_transfer_one() - perform a single transfer
240c3e4bc54SBeniamino Galvani  * @master:	the SPI master
241c3e4bc54SBeniamino Galvani  * @spi:	the SPI device
242c3e4bc54SBeniamino Galvani  * @xfer:	the current SPI transfer
243c3e4bc54SBeniamino Galvani  * Return:	0 on success, a negative value on error
244c3e4bc54SBeniamino Galvani  */
meson_spifc_transfer_one(struct spi_master * master,struct spi_device * spi,struct spi_transfer * xfer)245c3e4bc54SBeniamino Galvani static int meson_spifc_transfer_one(struct spi_master *master,
246c3e4bc54SBeniamino Galvani 				    struct spi_device *spi,
247c3e4bc54SBeniamino Galvani 				    struct spi_transfer *xfer)
248c3e4bc54SBeniamino Galvani {
249c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc = spi_master_get_devdata(master);
250c3e4bc54SBeniamino Galvani 	int len, done = 0, ret = 0;
251c3e4bc54SBeniamino Galvani 
252c3e4bc54SBeniamino Galvani 	meson_spifc_setup_speed(spifc, xfer->speed_hz);
253c3e4bc54SBeniamino Galvani 
254c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0);
255c3e4bc54SBeniamino Galvani 
256c3e4bc54SBeniamino Galvani 	while (done < xfer->len && !ret) {
257c3e4bc54SBeniamino Galvani 		len = min_t(int, xfer->len - done, SPIFC_BUFFER_SIZE);
258c3e4bc54SBeniamino Galvani 		ret = meson_spifc_txrx(spifc, xfer, done, len,
259c3e4bc54SBeniamino Galvani 				       spi_transfer_is_last(master, xfer),
260c3e4bc54SBeniamino Galvani 				       done + len >= xfer->len);
261c3e4bc54SBeniamino Galvani 		done += len;
262c3e4bc54SBeniamino Galvani 	}
263c3e4bc54SBeniamino Galvani 
264c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB,
265c3e4bc54SBeniamino Galvani 			   CTRL_ENABLE_AHB);
266c3e4bc54SBeniamino Galvani 
267c3e4bc54SBeniamino Galvani 	return ret;
268c3e4bc54SBeniamino Galvani }
269c3e4bc54SBeniamino Galvani 
270c3e4bc54SBeniamino Galvani /**
271c3e4bc54SBeniamino Galvani  * meson_spifc_hw_init() - reset and initialize the SPI controller
272c3e4bc54SBeniamino Galvani  * @spifc:	the Meson SPI device
273c3e4bc54SBeniamino Galvani  */
meson_spifc_hw_init(struct meson_spifc * spifc)274c3e4bc54SBeniamino Galvani static void meson_spifc_hw_init(struct meson_spifc *spifc)
275c3e4bc54SBeniamino Galvani {
276c3e4bc54SBeniamino Galvani 	/* reset device */
277c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST,
278c3e4bc54SBeniamino Galvani 			   SLAVE_SW_RST);
279c3e4bc54SBeniamino Galvani 	/* disable compatible mode */
280c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0);
281c3e4bc54SBeniamino Galvani 	/* set master mode */
282c3e4bc54SBeniamino Galvani 	regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0);
283c3e4bc54SBeniamino Galvani }
284c3e4bc54SBeniamino Galvani 
meson_spifc_probe(struct platform_device * pdev)285c3e4bc54SBeniamino Galvani static int meson_spifc_probe(struct platform_device *pdev)
286c3e4bc54SBeniamino Galvani {
287c3e4bc54SBeniamino Galvani 	struct spi_master *master;
288c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc;
289c3e4bc54SBeniamino Galvani 	void __iomem *base;
290c3e4bc54SBeniamino Galvani 	unsigned int rate;
291c3e4bc54SBeniamino Galvani 	int ret = 0;
292c3e4bc54SBeniamino Galvani 
293c3e4bc54SBeniamino Galvani 	master = spi_alloc_master(&pdev->dev, sizeof(struct meson_spifc));
294c3e4bc54SBeniamino Galvani 	if (!master)
295c3e4bc54SBeniamino Galvani 		return -ENOMEM;
296c3e4bc54SBeniamino Galvani 
297c3e4bc54SBeniamino Galvani 	platform_set_drvdata(pdev, master);
298c3e4bc54SBeniamino Galvani 
299c3e4bc54SBeniamino Galvani 	spifc = spi_master_get_devdata(master);
300c3e4bc54SBeniamino Galvani 	spifc->dev = &pdev->dev;
301c3e4bc54SBeniamino Galvani 
302425aa308SYueHaibing 	base = devm_platform_ioremap_resource(pdev, 0);
303c3e4bc54SBeniamino Galvani 	if (IS_ERR(base)) {
304c3e4bc54SBeniamino Galvani 		ret = PTR_ERR(base);
305c3e4bc54SBeniamino Galvani 		goto out_err;
306c3e4bc54SBeniamino Galvani 	}
307c3e4bc54SBeniamino Galvani 
308c3e4bc54SBeniamino Galvani 	spifc->regmap = devm_regmap_init_mmio(spifc->dev, base,
309c3e4bc54SBeniamino Galvani 					      &spifc_regmap_config);
310c3e4bc54SBeniamino Galvani 	if (IS_ERR(spifc->regmap)) {
311c3e4bc54SBeniamino Galvani 		ret = PTR_ERR(spifc->regmap);
312c3e4bc54SBeniamino Galvani 		goto out_err;
313c3e4bc54SBeniamino Galvani 	}
314c3e4bc54SBeniamino Galvani 
315c3e4bc54SBeniamino Galvani 	spifc->clk = devm_clk_get(spifc->dev, NULL);
316c3e4bc54SBeniamino Galvani 	if (IS_ERR(spifc->clk)) {
317c3e4bc54SBeniamino Galvani 		dev_err(spifc->dev, "missing clock\n");
318c3e4bc54SBeniamino Galvani 		ret = PTR_ERR(spifc->clk);
319c3e4bc54SBeniamino Galvani 		goto out_err;
320c3e4bc54SBeniamino Galvani 	}
321c3e4bc54SBeniamino Galvani 
322c3e4bc54SBeniamino Galvani 	ret = clk_prepare_enable(spifc->clk);
323c3e4bc54SBeniamino Galvani 	if (ret) {
324c3e4bc54SBeniamino Galvani 		dev_err(spifc->dev, "can't prepare clock\n");
325c3e4bc54SBeniamino Galvani 		goto out_err;
326c3e4bc54SBeniamino Galvani 	}
327c3e4bc54SBeniamino Galvani 
328c3e4bc54SBeniamino Galvani 	rate = clk_get_rate(spifc->clk);
329c3e4bc54SBeniamino Galvani 
330c3e4bc54SBeniamino Galvani 	master->num_chipselect = 1;
331c3e4bc54SBeniamino Galvani 	master->dev.of_node = pdev->dev.of_node;
332c3e4bc54SBeniamino Galvani 	master->bits_per_word_mask = SPI_BPW_MASK(8);
333c3e4bc54SBeniamino Galvani 	master->auto_runtime_pm = true;
334c3e4bc54SBeniamino Galvani 	master->transfer_one = meson_spifc_transfer_one;
335c3e4bc54SBeniamino Galvani 	master->min_speed_hz = rate >> 6;
336c3e4bc54SBeniamino Galvani 	master->max_speed_hz = rate >> 1;
337c3e4bc54SBeniamino Galvani 
338c3e4bc54SBeniamino Galvani 	meson_spifc_hw_init(spifc);
339c3e4bc54SBeniamino Galvani 
340c3e4bc54SBeniamino Galvani 	pm_runtime_set_active(spifc->dev);
341c3e4bc54SBeniamino Galvani 	pm_runtime_enable(spifc->dev);
342c3e4bc54SBeniamino Galvani 
343c3e4bc54SBeniamino Galvani 	ret = devm_spi_register_master(spifc->dev, master);
344c3e4bc54SBeniamino Galvani 	if (ret) {
345c3e4bc54SBeniamino Galvani 		dev_err(spifc->dev, "failed to register spi master\n");
346c3e4bc54SBeniamino Galvani 		goto out_clk;
347c3e4bc54SBeniamino Galvani 	}
348c3e4bc54SBeniamino Galvani 
349c3e4bc54SBeniamino Galvani 	return 0;
350c3e4bc54SBeniamino Galvani out_clk:
351c3e4bc54SBeniamino Galvani 	clk_disable_unprepare(spifc->clk);
35269c1b875SMiaoqian Lin 	pm_runtime_disable(spifc->dev);
353c3e4bc54SBeniamino Galvani out_err:
354c3e4bc54SBeniamino Galvani 	spi_master_put(master);
355c3e4bc54SBeniamino Galvani 	return ret;
356c3e4bc54SBeniamino Galvani }
357c3e4bc54SBeniamino Galvani 
meson_spifc_remove(struct platform_device * pdev)358*a4f5ad11SUwe Kleine-König static void meson_spifc_remove(struct platform_device *pdev)
359c3e4bc54SBeniamino Galvani {
360c3e4bc54SBeniamino Galvani 	struct spi_master *master = platform_get_drvdata(pdev);
361c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc = spi_master_get_devdata(master);
362c3e4bc54SBeniamino Galvani 
363c3e4bc54SBeniamino Galvani 	pm_runtime_get_sync(&pdev->dev);
364c3e4bc54SBeniamino Galvani 	clk_disable_unprepare(spifc->clk);
365c3e4bc54SBeniamino Galvani 	pm_runtime_disable(&pdev->dev);
366c3e4bc54SBeniamino Galvani }
367c3e4bc54SBeniamino Galvani 
368c3e4bc54SBeniamino Galvani #ifdef CONFIG_PM_SLEEP
meson_spifc_suspend(struct device * dev)369c3e4bc54SBeniamino Galvani static int meson_spifc_suspend(struct device *dev)
370c3e4bc54SBeniamino Galvani {
371c3e4bc54SBeniamino Galvani 	struct spi_master *master = dev_get_drvdata(dev);
372c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc = spi_master_get_devdata(master);
373c3e4bc54SBeniamino Galvani 	int ret;
374c3e4bc54SBeniamino Galvani 
375c3e4bc54SBeniamino Galvani 	ret = spi_master_suspend(master);
376c3e4bc54SBeniamino Galvani 	if (ret)
377c3e4bc54SBeniamino Galvani 		return ret;
378c3e4bc54SBeniamino Galvani 
379c3e4bc54SBeniamino Galvani 	if (!pm_runtime_suspended(dev))
380c3e4bc54SBeniamino Galvani 		clk_disable_unprepare(spifc->clk);
381c3e4bc54SBeniamino Galvani 
382c3e4bc54SBeniamino Galvani 	return 0;
383c3e4bc54SBeniamino Galvani }
384c3e4bc54SBeniamino Galvani 
meson_spifc_resume(struct device * dev)385c3e4bc54SBeniamino Galvani static int meson_spifc_resume(struct device *dev)
386c3e4bc54SBeniamino Galvani {
387c3e4bc54SBeniamino Galvani 	struct spi_master *master = dev_get_drvdata(dev);
388c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc = spi_master_get_devdata(master);
389c3e4bc54SBeniamino Galvani 	int ret;
390c3e4bc54SBeniamino Galvani 
391c3e4bc54SBeniamino Galvani 	if (!pm_runtime_suspended(dev)) {
392c3e4bc54SBeniamino Galvani 		ret = clk_prepare_enable(spifc->clk);
393c3e4bc54SBeniamino Galvani 		if (ret)
394c3e4bc54SBeniamino Galvani 			return ret;
395c3e4bc54SBeniamino Galvani 	}
396c3e4bc54SBeniamino Galvani 
397c3e4bc54SBeniamino Galvani 	meson_spifc_hw_init(spifc);
398c3e4bc54SBeniamino Galvani 
399c3e4bc54SBeniamino Galvani 	ret = spi_master_resume(master);
400c3e4bc54SBeniamino Galvani 	if (ret)
401c3e4bc54SBeniamino Galvani 		clk_disable_unprepare(spifc->clk);
402c3e4bc54SBeniamino Galvani 
403c3e4bc54SBeniamino Galvani 	return ret;
404c3e4bc54SBeniamino Galvani }
405c3e4bc54SBeniamino Galvani #endif /* CONFIG_PM_SLEEP */
406c3e4bc54SBeniamino Galvani 
40747164fdbSRafael J. Wysocki #ifdef CONFIG_PM
meson_spifc_runtime_suspend(struct device * dev)408c3e4bc54SBeniamino Galvani static int meson_spifc_runtime_suspend(struct device *dev)
409c3e4bc54SBeniamino Galvani {
410c3e4bc54SBeniamino Galvani 	struct spi_master *master = dev_get_drvdata(dev);
411c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc = spi_master_get_devdata(master);
412c3e4bc54SBeniamino Galvani 
413c3e4bc54SBeniamino Galvani 	clk_disable_unprepare(spifc->clk);
414c3e4bc54SBeniamino Galvani 
415c3e4bc54SBeniamino Galvani 	return 0;
416c3e4bc54SBeniamino Galvani }
417c3e4bc54SBeniamino Galvani 
meson_spifc_runtime_resume(struct device * dev)418c3e4bc54SBeniamino Galvani static int meson_spifc_runtime_resume(struct device *dev)
419c3e4bc54SBeniamino Galvani {
420c3e4bc54SBeniamino Galvani 	struct spi_master *master = dev_get_drvdata(dev);
421c3e4bc54SBeniamino Galvani 	struct meson_spifc *spifc = spi_master_get_devdata(master);
422c3e4bc54SBeniamino Galvani 
423c3e4bc54SBeniamino Galvani 	return clk_prepare_enable(spifc->clk);
424c3e4bc54SBeniamino Galvani }
42547164fdbSRafael J. Wysocki #endif /* CONFIG_PM */
426c3e4bc54SBeniamino Galvani 
427c3e4bc54SBeniamino Galvani static const struct dev_pm_ops meson_spifc_pm_ops = {
428c3e4bc54SBeniamino Galvani 	SET_SYSTEM_SLEEP_PM_OPS(meson_spifc_suspend, meson_spifc_resume)
429c3e4bc54SBeniamino Galvani 	SET_RUNTIME_PM_OPS(meson_spifc_runtime_suspend,
430c3e4bc54SBeniamino Galvani 			   meson_spifc_runtime_resume,
431c3e4bc54SBeniamino Galvani 			   NULL)
432c3e4bc54SBeniamino Galvani };
433c3e4bc54SBeniamino Galvani 
434c3e4bc54SBeniamino Galvani static const struct of_device_id meson_spifc_dt_match[] = {
435c3e4bc54SBeniamino Galvani 	{ .compatible = "amlogic,meson6-spifc", },
4362f58ea64SNeil Armstrong 	{ .compatible = "amlogic,meson-gxbb-spifc", },
437c3e4bc54SBeniamino Galvani 	{ },
438c3e4bc54SBeniamino Galvani };
439c9e97b3cSLuis de Bethencourt MODULE_DEVICE_TABLE(of, meson_spifc_dt_match);
440c3e4bc54SBeniamino Galvani 
441c3e4bc54SBeniamino Galvani static struct platform_driver meson_spifc_driver = {
442c3e4bc54SBeniamino Galvani 	.probe	= meson_spifc_probe,
443*a4f5ad11SUwe Kleine-König 	.remove_new = meson_spifc_remove,
444c3e4bc54SBeniamino Galvani 	.driver	= {
445c3e4bc54SBeniamino Galvani 		.name		= "meson-spifc",
446c3e4bc54SBeniamino Galvani 		.of_match_table	= of_match_ptr(meson_spifc_dt_match),
447c3e4bc54SBeniamino Galvani 		.pm		= &meson_spifc_pm_ops,
448c3e4bc54SBeniamino Galvani 	},
449c3e4bc54SBeniamino Galvani };
450c3e4bc54SBeniamino Galvani 
451c3e4bc54SBeniamino Galvani module_platform_driver(meson_spifc_driver);
452c3e4bc54SBeniamino Galvani 
453c3e4bc54SBeniamino Galvani MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
454c3e4bc54SBeniamino Galvani MODULE_DESCRIPTION("Amlogic Meson SPIFC driver");
455c3e4bc54SBeniamino Galvani MODULE_LICENSE("GPL v2");
456