1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for Amlogic Meson SPI flash controller (SPIFC)
5 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
9 #include <linux/delay.h>
10 #include <linux/device.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/regmap.h>
18 #include <linux/spi/spi.h>
19 #include <linux/types.h>
25 #define REG_CTRL1 0x0c
26 #define REG_STATUS 0x10
27 #define REG_CTRL2 0x14
28 #define REG_CLOCK 0x18
30 #define REG_USER1 0x20
31 #define REG_USER2 0x24
32 #define REG_USER3 0x28
33 #define REG_USER4 0x2c
34 #define REG_SLAVE 0x30
35 #define REG_SLAVE1 0x34
36 #define REG_SLAVE2 0x38
37 #define REG_SLAVE3 0x3c
43 #define CMD_USER BIT(18)
44 #define CTRL_ENABLE_AHB BIT(17)
45 #define CLOCK_SOURCE BIT(31)
46 #define CLOCK_DIV_SHIFT 12
47 #define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT)
48 #define CLOCK_CNT_HIGH_SHIFT 6
49 #define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT)
50 #define CLOCK_CNT_LOW_SHIFT 0
51 #define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT)
52 #define USER_DIN_EN_MS BIT(0)
53 #define USER_CMP_MODE BIT(2)
54 #define USER_UC_DOUT_SEL BIT(27)
55 #define USER_UC_DIN_SEL BIT(28)
56 #define USER_UC_MASK ((BIT(5) - 1) << 27)
57 #define USER1_BN_UC_DOUT_SHIFT 17
58 #define USER1_BN_UC_DOUT_MASK (0xff << 16)
59 #define USER1_BN_UC_DIN_SHIFT 8
60 #define USER1_BN_UC_DIN_MASK (0xff << 8)
61 #define USER4_CS_ACT BIT(30)
62 #define SLAVE_TRST_DONE BIT(4)
63 #define SLAVE_OP_MODE BIT(30)
64 #define SLAVE_SW_RST BIT(31)
66 #define SPIFC_BUFFER_SIZE 64
70 * @master: the SPI master
71 * @regmap: regmap for device registers
72 * @clk: input clock of the built-in baud rate generator
73 * @device: the device structure
76 struct spi_master
*master
;
77 struct regmap
*regmap
;
82 static const struct regmap_config spifc_regmap_config
= {
86 .max_register
= REG_MAX
,
90 * meson_spifc_wait_ready() - wait for the current operation to terminate
91 * @spifc: the Meson SPI device
92 * Return: 0 on success, a negative value on error
94 static int meson_spifc_wait_ready(struct meson_spifc
*spifc
)
96 unsigned long deadline
= jiffies
+ msecs_to_jiffies(5);
100 regmap_read(spifc
->regmap
, REG_SLAVE
, &data
);
101 if (data
& SLAVE_TRST_DONE
)
104 } while (!time_after(jiffies
, deadline
));
110 * meson_spifc_drain_buffer() - copy data from device buffer to memory
111 * @spifc: the Meson SPI device
112 * @buf: the destination buffer
113 * @len: number of bytes to copy
115 static void meson_spifc_drain_buffer(struct meson_spifc
*spifc
, u8
*buf
,
122 regmap_read(spifc
->regmap
, REG_C0
+ i
, &data
);
125 *((u32
*)buf
) = data
;
128 memcpy(buf
, &data
, len
- i
);
136 * meson_spifc_fill_buffer() - copy data from memory to device buffer
137 * @spifc: the Meson SPI device
138 * @buf: the source buffer
139 * @len: number of bytes to copy
141 static void meson_spifc_fill_buffer(struct meson_spifc
*spifc
, const u8
*buf
,
151 memcpy(&data
, buf
, len
- i
);
153 regmap_write(spifc
->regmap
, REG_C0
+ i
, data
);
161 * meson_spifc_setup_speed() - program the clock divider
162 * @spifc: the Meson SPI device
163 * @speed: desired speed in Hz
165 static void meson_spifc_setup_speed(struct meson_spifc
*spifc
, u32 speed
)
167 unsigned long parent
, value
;
170 parent
= clk_get_rate(spifc
->clk
);
171 n
= max_t(int, parent
/ speed
- 1, 1);
173 dev_dbg(spifc
->dev
, "parent %lu, speed %u, n %d\n", parent
,
176 value
= (n
<< CLOCK_DIV_SHIFT
) & CLOCK_DIV_MASK
;
177 value
|= (n
<< CLOCK_CNT_LOW_SHIFT
) & CLOCK_CNT_LOW_MASK
;
178 value
|= (((n
+ 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT
) &
181 regmap_write(spifc
->regmap
, REG_CLOCK
, value
);
185 * meson_spifc_txrx() - transfer a chunk of data
186 * @spifc: the Meson SPI device
187 * @xfer: the current SPI transfer
188 * @offset: offset of the data to transfer
189 * @len: length of the data to transfer
190 * @last_xfer: whether this is the last transfer of the message
191 * @last_chunk: whether this is the last chunk of the transfer
192 * Return: 0 on success, a negative value on error
194 static int meson_spifc_txrx(struct meson_spifc
*spifc
,
195 struct spi_transfer
*xfer
,
196 int offset
, int len
, bool last_xfer
,
203 meson_spifc_fill_buffer(spifc
, xfer
->tx_buf
+ offset
, len
);
205 /* enable DOUT stage */
206 regmap_update_bits(spifc
->regmap
, REG_USER
, USER_UC_MASK
,
208 regmap_write(spifc
->regmap
, REG_USER1
,
209 (8 * len
- 1) << USER1_BN_UC_DOUT_SHIFT
);
211 /* enable data input during DOUT */
212 regmap_update_bits(spifc
->regmap
, REG_USER
, USER_DIN_EN_MS
,
217 keep_cs
= xfer
->cs_change
;
219 keep_cs
= !xfer
->cs_change
;
222 regmap_update_bits(spifc
->regmap
, REG_USER4
, USER4_CS_ACT
,
223 keep_cs
? USER4_CS_ACT
: 0);
225 /* clear transition done bit */
226 regmap_update_bits(spifc
->regmap
, REG_SLAVE
, SLAVE_TRST_DONE
, 0);
228 regmap_update_bits(spifc
->regmap
, REG_CMD
, CMD_USER
, CMD_USER
);
230 ret
= meson_spifc_wait_ready(spifc
);
232 if (!ret
&& xfer
->rx_buf
)
233 meson_spifc_drain_buffer(spifc
, xfer
->rx_buf
+ offset
, len
);
239 * meson_spifc_transfer_one() - perform a single transfer
240 * @master: the SPI master
241 * @spi: the SPI device
242 * @xfer: the current SPI transfer
243 * Return: 0 on success, a negative value on error
245 static int meson_spifc_transfer_one(struct spi_master
*master
,
246 struct spi_device
*spi
,
247 struct spi_transfer
*xfer
)
249 struct meson_spifc
*spifc
= spi_master_get_devdata(master
);
250 int len
, done
= 0, ret
= 0;
252 meson_spifc_setup_speed(spifc
, xfer
->speed_hz
);
254 regmap_update_bits(spifc
->regmap
, REG_CTRL
, CTRL_ENABLE_AHB
, 0);
256 while (done
< xfer
->len
&& !ret
) {
257 len
= min_t(int, xfer
->len
- done
, SPIFC_BUFFER_SIZE
);
258 ret
= meson_spifc_txrx(spifc
, xfer
, done
, len
,
259 spi_transfer_is_last(master
, xfer
),
260 done
+ len
>= xfer
->len
);
264 regmap_update_bits(spifc
->regmap
, REG_CTRL
, CTRL_ENABLE_AHB
,
271 * meson_spifc_hw_init() - reset and initialize the SPI controller
272 * @spifc: the Meson SPI device
274 static void meson_spifc_hw_init(struct meson_spifc
*spifc
)
277 regmap_update_bits(spifc
->regmap
, REG_SLAVE
, SLAVE_SW_RST
,
279 /* disable compatible mode */
280 regmap_update_bits(spifc
->regmap
, REG_USER
, USER_CMP_MODE
, 0);
281 /* set master mode */
282 regmap_update_bits(spifc
->regmap
, REG_SLAVE
, SLAVE_OP_MODE
, 0);
285 static int meson_spifc_probe(struct platform_device
*pdev
)
287 struct spi_master
*master
;
288 struct meson_spifc
*spifc
;
289 struct resource
*res
;
294 master
= spi_alloc_master(&pdev
->dev
, sizeof(struct meson_spifc
));
298 platform_set_drvdata(pdev
, master
);
300 spifc
= spi_master_get_devdata(master
);
301 spifc
->dev
= &pdev
->dev
;
303 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
304 base
= devm_ioremap_resource(spifc
->dev
, res
);
310 spifc
->regmap
= devm_regmap_init_mmio(spifc
->dev
, base
,
311 &spifc_regmap_config
);
312 if (IS_ERR(spifc
->regmap
)) {
313 ret
= PTR_ERR(spifc
->regmap
);
317 spifc
->clk
= devm_clk_get(spifc
->dev
, NULL
);
318 if (IS_ERR(spifc
->clk
)) {
319 dev_err(spifc
->dev
, "missing clock\n");
320 ret
= PTR_ERR(spifc
->clk
);
324 ret
= clk_prepare_enable(spifc
->clk
);
326 dev_err(spifc
->dev
, "can't prepare clock\n");
330 rate
= clk_get_rate(spifc
->clk
);
332 master
->num_chipselect
= 1;
333 master
->dev
.of_node
= pdev
->dev
.of_node
;
334 master
->bits_per_word_mask
= SPI_BPW_MASK(8);
335 master
->auto_runtime_pm
= true;
336 master
->transfer_one
= meson_spifc_transfer_one
;
337 master
->min_speed_hz
= rate
>> 6;
338 master
->max_speed_hz
= rate
>> 1;
340 meson_spifc_hw_init(spifc
);
342 pm_runtime_set_active(spifc
->dev
);
343 pm_runtime_enable(spifc
->dev
);
345 ret
= devm_spi_register_master(spifc
->dev
, master
);
347 dev_err(spifc
->dev
, "failed to register spi master\n");
353 clk_disable_unprepare(spifc
->clk
);
355 spi_master_put(master
);
359 static int meson_spifc_remove(struct platform_device
*pdev
)
361 struct spi_master
*master
= platform_get_drvdata(pdev
);
362 struct meson_spifc
*spifc
= spi_master_get_devdata(master
);
364 pm_runtime_get_sync(&pdev
->dev
);
365 clk_disable_unprepare(spifc
->clk
);
366 pm_runtime_disable(&pdev
->dev
);
371 #ifdef CONFIG_PM_SLEEP
372 static int meson_spifc_suspend(struct device
*dev
)
374 struct spi_master
*master
= dev_get_drvdata(dev
);
375 struct meson_spifc
*spifc
= spi_master_get_devdata(master
);
378 ret
= spi_master_suspend(master
);
382 if (!pm_runtime_suspended(dev
))
383 clk_disable_unprepare(spifc
->clk
);
388 static int meson_spifc_resume(struct device
*dev
)
390 struct spi_master
*master
= dev_get_drvdata(dev
);
391 struct meson_spifc
*spifc
= spi_master_get_devdata(master
);
394 if (!pm_runtime_suspended(dev
)) {
395 ret
= clk_prepare_enable(spifc
->clk
);
400 meson_spifc_hw_init(spifc
);
402 ret
= spi_master_resume(master
);
404 clk_disable_unprepare(spifc
->clk
);
408 #endif /* CONFIG_PM_SLEEP */
411 static int meson_spifc_runtime_suspend(struct device
*dev
)
413 struct spi_master
*master
= dev_get_drvdata(dev
);
414 struct meson_spifc
*spifc
= spi_master_get_devdata(master
);
416 clk_disable_unprepare(spifc
->clk
);
421 static int meson_spifc_runtime_resume(struct device
*dev
)
423 struct spi_master
*master
= dev_get_drvdata(dev
);
424 struct meson_spifc
*spifc
= spi_master_get_devdata(master
);
426 return clk_prepare_enable(spifc
->clk
);
428 #endif /* CONFIG_PM */
430 static const struct dev_pm_ops meson_spifc_pm_ops
= {
431 SET_SYSTEM_SLEEP_PM_OPS(meson_spifc_suspend
, meson_spifc_resume
)
432 SET_RUNTIME_PM_OPS(meson_spifc_runtime_suspend
,
433 meson_spifc_runtime_resume
,
437 static const struct of_device_id meson_spifc_dt_match
[] = {
438 { .compatible
= "amlogic,meson6-spifc", },
439 { .compatible
= "amlogic,meson-gxbb-spifc", },
442 MODULE_DEVICE_TABLE(of
, meson_spifc_dt_match
);
444 static struct platform_driver meson_spifc_driver
= {
445 .probe
= meson_spifc_probe
,
446 .remove
= meson_spifc_remove
,
448 .name
= "meson-spifc",
449 .of_match_table
= of_match_ptr(meson_spifc_dt_match
),
450 .pm
= &meson_spifc_pm_ops
,
454 module_platform_driver(meson_spifc_driver
);
456 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
457 MODULE_DESCRIPTION("Amlogic Meson SPIFC driver");
458 MODULE_LICENSE("GPL v2");