Lines Matching +full:meson6 +full:- +full:spifc
1 // SPDX-License-Identifier: GPL-2.0+
3 // Driver for Amlogic Meson SPI flash controller (SPIFC)
56 #define USER_UC_MASK ((BIT(5) - 1) << 27)
72 * @clk: input clock of the built-in baud rate generator
90 * meson_spifc_wait_ready() - wait for the current operation to terminate
91 * @spifc: the Meson SPI device
94 static int meson_spifc_wait_ready(struct meson_spifc *spifc) in meson_spifc_wait_ready() argument
100 regmap_read(spifc->regmap, REG_SLAVE, &data); in meson_spifc_wait_ready()
106 return -ETIMEDOUT; in meson_spifc_wait_ready()
110 * meson_spifc_drain_buffer() - copy data from device buffer to memory
111 * @spifc: the Meson SPI device
115 static void meson_spifc_drain_buffer(struct meson_spifc *spifc, u8 *buf, in meson_spifc_drain_buffer() argument
122 regmap_read(spifc->regmap, REG_C0 + i, &data); in meson_spifc_drain_buffer()
124 if (len - i >= 4) { in meson_spifc_drain_buffer()
128 memcpy(buf, &data, len - i); in meson_spifc_drain_buffer()
136 * meson_spifc_fill_buffer() - copy data from memory to device buffer
137 * @spifc: the Meson SPI device
141 static void meson_spifc_fill_buffer(struct meson_spifc *spifc, const u8 *buf, in meson_spifc_fill_buffer() argument
148 if (len - i >= 4) in meson_spifc_fill_buffer()
151 memcpy(&data, buf, len - i); in meson_spifc_fill_buffer()
153 regmap_write(spifc->regmap, REG_C0 + i, data); in meson_spifc_fill_buffer()
161 * meson_spifc_setup_speed() - program the clock divider
162 * @spifc: the Meson SPI device
165 static void meson_spifc_setup_speed(struct meson_spifc *spifc, u32 speed) in meson_spifc_setup_speed() argument
170 parent = clk_get_rate(spifc->clk); in meson_spifc_setup_speed()
171 n = max_t(int, parent / speed - 1, 1); in meson_spifc_setup_speed()
173 dev_dbg(spifc->dev, "parent %lu, speed %u, n %d\n", parent, in meson_spifc_setup_speed()
178 value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) & in meson_spifc_setup_speed()
181 regmap_write(spifc->regmap, REG_CLOCK, value); in meson_spifc_setup_speed()
185 * meson_spifc_txrx() - transfer a chunk of data
186 * @spifc: the Meson SPI device
194 static int meson_spifc_txrx(struct meson_spifc *spifc, in meson_spifc_txrx() argument
202 if (xfer->tx_buf) in meson_spifc_txrx()
203 meson_spifc_fill_buffer(spifc, xfer->tx_buf + offset, len); in meson_spifc_txrx()
206 regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK, in meson_spifc_txrx()
208 regmap_write(spifc->regmap, REG_USER1, in meson_spifc_txrx()
209 (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT); in meson_spifc_txrx()
212 regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS, in meson_spifc_txrx()
217 keep_cs = xfer->cs_change; in meson_spifc_txrx()
219 keep_cs = !xfer->cs_change; in meson_spifc_txrx()
222 regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT, in meson_spifc_txrx()
226 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0); in meson_spifc_txrx()
228 regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER); in meson_spifc_txrx()
230 ret = meson_spifc_wait_ready(spifc); in meson_spifc_txrx()
232 if (!ret && xfer->rx_buf) in meson_spifc_txrx()
233 meson_spifc_drain_buffer(spifc, xfer->rx_buf + offset, len); in meson_spifc_txrx()
239 * meson_spifc_transfer_one() - perform a single transfer
249 struct meson_spifc *spifc = spi_master_get_devdata(master); in meson_spifc_transfer_one() local
252 meson_spifc_setup_speed(spifc, xfer->speed_hz); in meson_spifc_transfer_one()
254 regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0); in meson_spifc_transfer_one()
256 while (done < xfer->len && !ret) { in meson_spifc_transfer_one()
257 len = min_t(int, xfer->len - done, SPIFC_BUFFER_SIZE); in meson_spifc_transfer_one()
258 ret = meson_spifc_txrx(spifc, xfer, done, len, in meson_spifc_transfer_one()
260 done + len >= xfer->len); in meson_spifc_transfer_one()
264 regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, in meson_spifc_transfer_one()
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) in meson_spifc_hw_init() argument
277 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST, in meson_spifc_hw_init()
280 regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0); in meson_spifc_hw_init()
282 regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0); in meson_spifc_hw_init()
288 struct meson_spifc *spifc; in meson_spifc_probe() local
293 master = spi_alloc_master(&pdev->dev, sizeof(struct meson_spifc)); in meson_spifc_probe()
295 return -ENOMEM; in meson_spifc_probe()
299 spifc = spi_master_get_devdata(master); in meson_spifc_probe()
300 spifc->dev = &pdev->dev; in meson_spifc_probe()
308 spifc->regmap = devm_regmap_init_mmio(spifc->dev, base, in meson_spifc_probe()
310 if (IS_ERR(spifc->regmap)) { in meson_spifc_probe()
311 ret = PTR_ERR(spifc->regmap); in meson_spifc_probe()
315 spifc->clk = devm_clk_get(spifc->dev, NULL); in meson_spifc_probe()
316 if (IS_ERR(spifc->clk)) { in meson_spifc_probe()
317 dev_err(spifc->dev, "missing clock\n"); in meson_spifc_probe()
318 ret = PTR_ERR(spifc->clk); in meson_spifc_probe()
322 ret = clk_prepare_enable(spifc->clk); in meson_spifc_probe()
324 dev_err(spifc->dev, "can't prepare clock\n"); in meson_spifc_probe()
328 rate = clk_get_rate(spifc->clk); in meson_spifc_probe()
330 master->num_chipselect = 1; in meson_spifc_probe()
331 master->dev.of_node = pdev->dev.of_node; in meson_spifc_probe()
332 master->bits_per_word_mask = SPI_BPW_MASK(8); in meson_spifc_probe()
333 master->auto_runtime_pm = true; in meson_spifc_probe()
334 master->transfer_one = meson_spifc_transfer_one; in meson_spifc_probe()
335 master->min_speed_hz = rate >> 6; in meson_spifc_probe()
336 master->max_speed_hz = rate >> 1; in meson_spifc_probe()
338 meson_spifc_hw_init(spifc); in meson_spifc_probe()
340 pm_runtime_set_active(spifc->dev); in meson_spifc_probe()
341 pm_runtime_enable(spifc->dev); in meson_spifc_probe()
343 ret = devm_spi_register_master(spifc->dev, master); in meson_spifc_probe()
345 dev_err(spifc->dev, "failed to register spi master\n"); in meson_spifc_probe()
351 clk_disable_unprepare(spifc->clk); in meson_spifc_probe()
352 pm_runtime_disable(spifc->dev); in meson_spifc_probe()
361 struct meson_spifc *spifc = spi_master_get_devdata(master); in meson_spifc_remove() local
363 pm_runtime_get_sync(&pdev->dev); in meson_spifc_remove()
364 clk_disable_unprepare(spifc->clk); in meson_spifc_remove()
365 pm_runtime_disable(&pdev->dev); in meson_spifc_remove()
374 struct meson_spifc *spifc = spi_master_get_devdata(master); in meson_spifc_suspend() local
382 clk_disable_unprepare(spifc->clk); in meson_spifc_suspend()
390 struct meson_spifc *spifc = spi_master_get_devdata(master); in meson_spifc_resume() local
394 ret = clk_prepare_enable(spifc->clk); in meson_spifc_resume()
399 meson_spifc_hw_init(spifc); in meson_spifc_resume()
403 clk_disable_unprepare(spifc->clk); in meson_spifc_resume()
413 struct meson_spifc *spifc = spi_master_get_devdata(master); in meson_spifc_runtime_suspend() local
415 clk_disable_unprepare(spifc->clk); in meson_spifc_runtime_suspend()
423 struct meson_spifc *spifc = spi_master_get_devdata(master); in meson_spifc_runtime_resume() local
425 return clk_prepare_enable(spifc->clk); in meson_spifc_runtime_resume()
437 { .compatible = "amlogic,meson6-spifc", },
438 { .compatible = "amlogic,meson-gxbb-spifc", },
447 .name = "meson-spifc",
456 MODULE_DESCRIPTION("Amlogic Meson SPIFC driver");