Lines Matching full:spicc
2 * Driver for Amlogic Meson SPI communication controller (SPICC)
26 * The Meson SPICC controller could support DMA based transfers, but is not
174 static void meson_spicc_oen_enable(struct meson_spicc_device *spicc) in meson_spicc_oen_enable() argument
178 if (!spicc->data->has_oen) in meson_spicc_oen_enable()
181 conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) | in meson_spicc_oen_enable()
184 writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0); in meson_spicc_oen_enable()
187 static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc) in meson_spicc_txfull() argument
190 readl_relaxed(spicc->base + SPICC_STATREG)); in meson_spicc_txfull()
193 static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc) in meson_spicc_rxready() argument
196 readl_relaxed(spicc->base + SPICC_STATREG)); in meson_spicc_rxready()
199 static inline u32 meson_spicc_pull_data(struct meson_spicc_device *spicc) in meson_spicc_pull_data() argument
201 unsigned int bytes = spicc->bytes_per_word; in meson_spicc_pull_data()
207 byte = *spicc->tx_buf++; in meson_spicc_pull_data()
212 spicc->tx_remain--; in meson_spicc_pull_data()
216 static inline void meson_spicc_push_data(struct meson_spicc_device *spicc, in meson_spicc_push_data() argument
219 unsigned int bytes = spicc->bytes_per_word; in meson_spicc_push_data()
225 *spicc->rx_buf++ = byte; in meson_spicc_push_data()
229 spicc->rx_remain--; in meson_spicc_push_data()
232 static inline void meson_spicc_rx(struct meson_spicc_device *spicc) in meson_spicc_rx() argument
235 while (spicc->rx_remain && in meson_spicc_rx()
236 meson_spicc_rxready(spicc)) in meson_spicc_rx()
237 meson_spicc_push_data(spicc, in meson_spicc_rx()
238 readl_relaxed(spicc->base + SPICC_RXDATA)); in meson_spicc_rx()
241 static inline void meson_spicc_tx(struct meson_spicc_device *spicc) in meson_spicc_tx() argument
244 while (spicc->tx_remain && in meson_spicc_tx()
245 !meson_spicc_txfull(spicc)) in meson_spicc_tx()
246 writel_relaxed(meson_spicc_pull_data(spicc), in meson_spicc_tx()
247 spicc->base + SPICC_TXDATA); in meson_spicc_tx()
250 static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc) in meson_spicc_setup_burst() argument
254 spicc->xfer_remain / in meson_spicc_setup_burst()
255 spicc->bytes_per_word, in meson_spicc_setup_burst()
256 spicc->data->fifo_size); in meson_spicc_setup_burst()
258 spicc->tx_remain = burst_len; in meson_spicc_setup_burst()
259 spicc->rx_remain = burst_len; in meson_spicc_setup_burst()
260 spicc->xfer_remain -= burst_len * spicc->bytes_per_word; in meson_spicc_setup_burst()
266 spicc->base + SPICC_CONREG); in meson_spicc_setup_burst()
269 meson_spicc_tx(spicc); in meson_spicc_setup_burst()
274 struct meson_spicc_device *spicc = (void *) data; in meson_spicc_irq() local
276 writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG); in meson_spicc_irq()
279 meson_spicc_rx(spicc); in meson_spicc_irq()
281 if (!spicc->xfer_remain) { in meson_spicc_irq()
283 writel(0, spicc->base + SPICC_INTREG); in meson_spicc_irq()
285 spi_finalize_current_transfer(spicc->master); in meson_spicc_irq()
291 meson_spicc_setup_burst(spicc); in meson_spicc_irq()
294 writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); in meson_spicc_irq()
299 static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc) in meson_spicc_auto_io_delay() argument
305 if (spicc->data->has_enhance_clk_div) { in meson_spicc_auto_io_delay()
307 readl_relaxed(spicc->base + SPICC_ENH_CTL0)); in meson_spicc_auto_io_delay()
312 readl_relaxed(spicc->base + SPICC_CONREG)); in meson_spicc_auto_io_delay()
319 hz = clk_get_rate(spicc->clk); in meson_spicc_auto_io_delay()
334 conf = readl_relaxed(spicc->base + SPICC_TESTREG); in meson_spicc_auto_io_delay()
339 writel_relaxed(conf, spicc->base + SPICC_TESTREG); in meson_spicc_auto_io_delay()
342 static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc, in meson_spicc_setup_xfer() argument
348 conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG); in meson_spicc_setup_xfer()
353 (spicc->bytes_per_word << 3) - 1); in meson_spicc_setup_xfer()
357 writel_relaxed(conf, spicc->base + SPICC_CONREG); in meson_spicc_setup_xfer()
359 clk_set_rate(spicc->clk, xfer->speed_hz); in meson_spicc_setup_xfer()
361 meson_spicc_auto_io_delay(spicc); in meson_spicc_setup_xfer()
363 writel_relaxed(0, spicc->base + SPICC_DMAREG); in meson_spicc_setup_xfer()
366 static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc) in meson_spicc_reset_fifo() argument
368 if (spicc->data->has_oen) in meson_spicc_reset_fifo()
371 spicc->base + SPICC_ENH_CTL0); in meson_spicc_reset_fifo()
374 spicc->base + SPICC_TESTREG); in meson_spicc_reset_fifo()
376 while (meson_spicc_rxready(spicc)) in meson_spicc_reset_fifo()
377 readl_relaxed(spicc->base + SPICC_RXDATA); in meson_spicc_reset_fifo()
379 if (spicc->data->has_oen) in meson_spicc_reset_fifo()
381 spicc->base + SPICC_ENH_CTL0); in meson_spicc_reset_fifo()
388 struct meson_spicc_device *spicc = spi_master_get_devdata(master); in meson_spicc_transfer_one() local
391 spicc->xfer = xfer; in meson_spicc_transfer_one()
394 spicc->tx_buf = (u8 *)xfer->tx_buf; in meson_spicc_transfer_one()
395 spicc->rx_buf = (u8 *)xfer->rx_buf; in meson_spicc_transfer_one()
396 spicc->xfer_remain = xfer->len; in meson_spicc_transfer_one()
399 spicc->bytes_per_word = in meson_spicc_transfer_one()
400 DIV_ROUND_UP(spicc->xfer->bits_per_word, 8); in meson_spicc_transfer_one()
402 if (xfer->len % spicc->bytes_per_word) in meson_spicc_transfer_one()
406 meson_spicc_setup_xfer(spicc, xfer); in meson_spicc_transfer_one()
408 meson_spicc_reset_fifo(spicc); in meson_spicc_transfer_one()
411 meson_spicc_setup_burst(spicc); in meson_spicc_transfer_one()
414 writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG); in meson_spicc_transfer_one()
417 writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG); in meson_spicc_transfer_one()
425 struct meson_spicc_device *spicc = spi_master_get_devdata(master); in meson_spicc_prepare_message() local
427 u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK; in meson_spicc_prepare_message()
430 spicc->message = message; in meson_spicc_prepare_message()
467 writel_relaxed(conf, spicc->base + SPICC_CONREG); in meson_spicc_prepare_message()
470 writel_relaxed(0, spicc->base + SPICC_PERIODREG); in meson_spicc_prepare_message()
472 writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG); in meson_spicc_prepare_message()
479 struct meson_spicc_device *spicc = spi_master_get_devdata(master); in meson_spicc_unprepare_transfer() local
480 u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK; in meson_spicc_unprepare_transfer()
483 writel(0, spicc->base + SPICC_INTREG); in meson_spicc_unprepare_transfer()
485 device_reset_optional(&spicc->pdev->dev); in meson_spicc_unprepare_transfer()
488 writel_relaxed(conf, spicc->base + SPICC_CONREG); in meson_spicc_unprepare_transfer()
538 struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); in meson_spicc_pow2_recalc_rate() local
540 if (!spicc->master->cur_msg) in meson_spicc_pow2_recalc_rate()
550 struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); in meson_spicc_pow2_determine_rate() local
552 if (!spicc->master->cur_msg) in meson_spicc_pow2_determine_rate()
562 struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); in meson_spicc_pow2_set_rate() local
564 if (!spicc->master->cur_msg) in meson_spicc_pow2_set_rate()
576 static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) in meson_spicc_pow2_clk_init() argument
578 struct device *dev = &spicc->pdev->dev; in meson_spicc_pow2_clk_init()
600 if (spicc->data->has_pclk) in meson_spicc_pow2_clk_init()
601 parent_data[0].hw = __clk_get_hw(spicc->pclk); in meson_spicc_pow2_clk_init()
603 parent_data[0].hw = __clk_get_hw(spicc->core); in meson_spicc_pow2_clk_init()
625 spicc->pow2_div.shift = 16, in meson_spicc_pow2_clk_init()
626 spicc->pow2_div.width = 3, in meson_spicc_pow2_clk_init()
627 spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO, in meson_spicc_pow2_clk_init()
628 spicc->pow2_div.reg = spicc->base + SPICC_CONREG; in meson_spicc_pow2_clk_init()
629 spicc->pow2_div.hw.init = &init; in meson_spicc_pow2_clk_init()
631 spicc->clk = devm_clk_register(dev, &spicc->pow2_div.hw); in meson_spicc_pow2_clk_init()
632 if (WARN_ON(IS_ERR(spicc->clk))) in meson_spicc_pow2_clk_init()
633 return PTR_ERR(spicc->clk); in meson_spicc_pow2_clk_init()
638 static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) in meson_spicc_enh_clk_init() argument
640 struct device *dev = &spicc->pdev->dev; in meson_spicc_enh_clk_init()
664 if (spicc->data->has_pclk) in meson_spicc_enh_clk_init()
665 parent_data[0].hw = __clk_get_hw(spicc->pclk); in meson_spicc_enh_clk_init()
667 parent_data[0].hw = __clk_get_hw(spicc->core); in meson_spicc_enh_clk_init()
691 enh_div->reg = spicc->base + SPICC_ENH_CTL0; in meson_spicc_enh_clk_init()
705 parent_data[0].hw = &spicc->pow2_div.hw; in meson_spicc_enh_clk_init()
712 mux->reg = spicc->base + SPICC_ENH_CTL0; in meson_spicc_enh_clk_init()
715 spicc->clk = devm_clk_register(dev, &mux->hw); in meson_spicc_enh_clk_init()
716 if (WARN_ON(IS_ERR(spicc->clk))) in meson_spicc_enh_clk_init()
717 return PTR_ERR(spicc->clk); in meson_spicc_enh_clk_init()
725 struct meson_spicc_device *spicc; in meson_spicc_probe() local
728 master = spi_alloc_master(&pdev->dev, sizeof(*spicc)); in meson_spicc_probe()
733 spicc = spi_master_get_devdata(master); in meson_spicc_probe()
734 spicc->master = master; in meson_spicc_probe()
736 spicc->data = of_device_get_match_data(&pdev->dev); in meson_spicc_probe()
737 if (!spicc->data) { in meson_spicc_probe()
743 spicc->pdev = pdev; in meson_spicc_probe()
744 platform_set_drvdata(pdev, spicc); in meson_spicc_probe()
746 spicc->base = devm_platform_ioremap_resource(pdev, 0); in meson_spicc_probe()
747 if (IS_ERR(spicc->base)) { in meson_spicc_probe()
749 ret = PTR_ERR(spicc->base); in meson_spicc_probe()
755 spicc->base + SPICC_CONREG); in meson_spicc_probe()
758 writel_relaxed(0, spicc->base + SPICC_INTREG); in meson_spicc_probe()
767 0, NULL, spicc); in meson_spicc_probe()
773 spicc->core = devm_clk_get(&pdev->dev, "core"); in meson_spicc_probe()
774 if (IS_ERR(spicc->core)) { in meson_spicc_probe()
776 ret = PTR_ERR(spicc->core); in meson_spicc_probe()
780 if (spicc->data->has_pclk) { in meson_spicc_probe()
781 spicc->pclk = devm_clk_get(&pdev->dev, "pclk"); in meson_spicc_probe()
782 if (IS_ERR(spicc->pclk)) { in meson_spicc_probe()
784 ret = PTR_ERR(spicc->pclk); in meson_spicc_probe()
789 ret = clk_prepare_enable(spicc->core); in meson_spicc_probe()
795 ret = clk_prepare_enable(spicc->pclk); in meson_spicc_probe()
811 master->min_speed_hz = spicc->data->min_speed_hz; in meson_spicc_probe()
812 master->max_speed_hz = spicc->data->max_speed_hz; in meson_spicc_probe()
820 meson_spicc_oen_enable(spicc); in meson_spicc_probe()
822 ret = meson_spicc_pow2_clk_init(spicc); in meson_spicc_probe()
828 if (spicc->data->has_enhance_clk_div) { in meson_spicc_probe()
829 ret = meson_spicc_enh_clk_init(spicc); in meson_spicc_probe()
845 clk_disable_unprepare(spicc->pclk); in meson_spicc_probe()
848 clk_disable_unprepare(spicc->core); in meson_spicc_probe()
858 struct meson_spicc_device *spicc = platform_get_drvdata(pdev); in meson_spicc_remove() local
861 writel(0, spicc->base + SPICC_CONREG); in meson_spicc_remove()
863 clk_disable_unprepare(spicc->core); in meson_spicc_remove()
864 clk_disable_unprepare(spicc->pclk); in meson_spicc_remove()
866 spi_master_put(spicc->master); in meson_spicc_remove()
896 .compatible = "amlogic,meson-gx-spicc",
900 .compatible = "amlogic,meson-axg-spicc",
904 .compatible = "amlogic,meson-g12a-spicc",
915 .name = "meson-spicc",