Lines Matching +full:spi +full:- +full:clk
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Broadcom BCMBCA High Speed SPI Controller driver
5 * Copyright 2000-2010 Broadcom Corporation
6 * Copyright 2012-2013 Jonas Gorski <jonas.gorski@gmail.com>
7 * Copyright 2019-2022 Broadcom Ltd
13 #include <linux/clk.h>
17 #include <linux/dma-mapping.h>
20 #include <linux/spi/spi.h>
23 #include <linux/spi/spi-mem.h>
99 #define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
116 struct clk *clk; member
117 struct clk *pll_clk;
132 return sprintf(buf, "%d\n", bs->wait_mode); in wait_mode_show()
143 return -EINVAL; in wait_mode_store()
147 return -EINVAL; in wait_mode_store()
150 mutex_lock(&bs->msg_mutex); in wait_mode_store()
151 bs->wait_mode = val; in wait_mode_store()
154 __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG); in wait_mode_store()
155 mutex_unlock(&bs->msg_mutex); in wait_mode_store()
180 mutex_lock(&bs->bus_mutex); in bcmbca_hsspi_set_cs()
182 reg = __raw_readl(bs->spim_ctrl); in bcmbca_hsspi_set_cs()
188 __raw_writel(reg, bs->spim_ctrl); in bcmbca_hsspi_set_cs()
190 mutex_unlock(&bs->bus_mutex); in bcmbca_hsspi_set_cs()
194 struct spi_device *spi, int hz) in bcmbca_hsspi_set_clk() argument
196 unsigned int profile = spi_get_chipselect(spi, 0); in bcmbca_hsspi_set_clk()
199 reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz)); in bcmbca_hsspi_set_clk()
201 bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile)); in bcmbca_hsspi_set_clk()
203 reg = __raw_readl(bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile)); in bcmbca_hsspi_set_clk()
208 __raw_writel(reg, bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile)); in bcmbca_hsspi_set_clk()
210 mutex_lock(&bs->bus_mutex); in bcmbca_hsspi_set_clk()
212 reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG); in bcmbca_hsspi_set_clk()
214 if (spi->mode & SPI_CPOL) in bcmbca_hsspi_set_clk()
216 __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG); in bcmbca_hsspi_set_clk()
218 mutex_unlock(&bs->bus_mutex); in bcmbca_hsspi_set_clk()
227 if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) { in bcmbca_hsspi_wait_cmd()
228 if (wait_for_completion_timeout(&bs->done, HZ) == 0) in bcmbca_hsspi_wait_cmd()
234 reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0)); in bcmbca_hsspi_wait_cmd()
245 dev_err(&bs->pdev->dev, "transfer timed out!\n"); in bcmbca_hsspi_wait_cmd()
250 static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t, in bcmbca_hsspi_do_txrx() argument
253 struct bcmbca_hsspi *bs = spi_controller_get_devdata(spi->controller); in bcmbca_hsspi_do_txrx()
254 unsigned int chip_select = spi_get_chipselect(spi, 0); in bcmbca_hsspi_do_txrx()
256 int pending = t->len; in bcmbca_hsspi_do_txrx()
258 const u8 *tx = t->tx_buf; in bcmbca_hsspi_do_txrx()
259 u8 *rx = t->rx_buf; in bcmbca_hsspi_do_txrx()
262 bcmbca_hsspi_set_clk(bs, spi, t->speed_hz); in bcmbca_hsspi_do_txrx()
272 step_size -= HSSPI_OPCODE_LEN; in bcmbca_hsspi_do_txrx()
274 if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) || in bcmbca_hsspi_do_txrx()
275 (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) { in bcmbca_hsspi_do_txrx()
278 if (t->rx_nbits == SPI_NBITS_DUAL) in bcmbca_hsspi_do_txrx()
280 if (t->tx_nbits == SPI_NBITS_DUAL) in bcmbca_hsspi_do_txrx()
285 bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select)); in bcmbca_hsspi_do_txrx()
290 reinit_completion(&bs->done); in bcmbca_hsspi_do_txrx()
292 memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step); in bcmbca_hsspi_do_txrx()
297 __raw_writew(val, bs->fifo); in bcmbca_hsspi_do_txrx()
300 if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) in bcmbca_hsspi_do_txrx()
302 bs->regs + HSSPI_INT_MASK_REG); in bcmbca_hsspi_do_txrx()
313 __raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0)); in bcmbca_hsspi_do_txrx()
315 if (bcmbca_hsspi_wait_cmd(bs, spi_get_chipselect(spi, 0))) in bcmbca_hsspi_do_txrx()
316 return -ETIMEDOUT; in bcmbca_hsspi_do_txrx()
318 pending -= curr_step; in bcmbca_hsspi_do_txrx()
321 memcpy_fromio(rx, bs->fifo, curr_step); in bcmbca_hsspi_do_txrx()
329 static int bcmbca_hsspi_setup(struct spi_device *spi) in bcmbca_hsspi_setup() argument
331 struct bcmbca_hsspi *bs = spi_controller_get_devdata(spi->controller); in bcmbca_hsspi_setup()
334 reg = __raw_readl(bs->regs + in bcmbca_hsspi_setup()
335 HSSPI_PROFILE_SIGNAL_CTRL_REG(spi_get_chipselect(spi, 0))); in bcmbca_hsspi_setup()
337 if (spi->mode & SPI_CPHA) in bcmbca_hsspi_setup()
341 __raw_writel(reg, bs->regs + in bcmbca_hsspi_setup()
342 HSSPI_PROFILE_SIGNAL_CTRL_REG(spi_get_chipselect(spi, 0))); in bcmbca_hsspi_setup()
344 mutex_lock(&bs->bus_mutex); in bcmbca_hsspi_setup()
345 reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG); in bcmbca_hsspi_setup()
347 if (spi->mode & SPI_CS_HIGH) in bcmbca_hsspi_setup()
348 reg |= BIT(spi_get_chipselect(spi, 0)); in bcmbca_hsspi_setup()
350 reg &= ~BIT(spi_get_chipselect(spi, 0)); in bcmbca_hsspi_setup()
351 __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG); in bcmbca_hsspi_setup()
353 if (spi->mode & SPI_CS_HIGH) in bcmbca_hsspi_setup()
354 bs->cs_polarity |= BIT(spi_get_chipselect(spi, 0)); in bcmbca_hsspi_setup()
356 bs->cs_polarity &= ~BIT(spi_get_chipselect(spi, 0)); in bcmbca_hsspi_setup()
358 reg = __raw_readl(bs->spim_ctrl); in bcmbca_hsspi_setup()
359 reg &= ~BIT(spi_get_chipselect(spi, 0) + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT); in bcmbca_hsspi_setup()
360 if (spi->mode & SPI_CS_HIGH) in bcmbca_hsspi_setup()
361 reg |= BIT(spi_get_chipselect(spi, 0) + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT); in bcmbca_hsspi_setup()
362 __raw_writel(reg, bs->spim_ctrl); in bcmbca_hsspi_setup()
364 mutex_unlock(&bs->bus_mutex); in bcmbca_hsspi_setup()
374 struct spi_device *spi = msg->spi; in bcmbca_hsspi_transfer_one() local
375 int status = -EINVAL; in bcmbca_hsspi_transfer_one()
378 mutex_lock(&bs->msg_mutex); in bcmbca_hsspi_transfer_one()
379 list_for_each_entry(t, &msg->transfers, transfer_list) { in bcmbca_hsspi_transfer_one()
380 status = bcmbca_hsspi_do_txrx(spi, t, msg); in bcmbca_hsspi_transfer_one()
386 if (t->cs_change) { in bcmbca_hsspi_transfer_one()
387 if (list_is_last(&t->transfer_list, &msg->transfers)) { in bcmbca_hsspi_transfer_one()
390 if (!t->cs_off) in bcmbca_hsspi_transfer_one()
391 bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false); in bcmbca_hsspi_transfer_one()
395 if (!list_next_entry(t, transfer_list)->cs_off) in bcmbca_hsspi_transfer_one()
396 bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), true); in bcmbca_hsspi_transfer_one()
398 } else if (!list_is_last(&t->transfer_list, &msg->transfers) && in bcmbca_hsspi_transfer_one()
399 t->cs_off != list_next_entry(t, transfer_list)->cs_off) { in bcmbca_hsspi_transfer_one()
400 bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), t->cs_off); in bcmbca_hsspi_transfer_one()
403 msg->actual_length += t->len; in bcmbca_hsspi_transfer_one()
406 mutex_unlock(&bs->msg_mutex); in bcmbca_hsspi_transfer_one()
409 bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false); in bcmbca_hsspi_transfer_one()
411 msg->status = status; in bcmbca_hsspi_transfer_one()
421 if (__raw_readl(bs->regs + HSSPI_INT_STATUS_MASKED_REG) == 0) in bcmbca_hsspi_interrupt()
424 __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG); in bcmbca_hsspi_interrupt()
425 __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); in bcmbca_hsspi_interrupt()
427 complete(&bs->done); in bcmbca_hsspi_interrupt()
439 struct device *dev = &pdev->dev; in bcmbca_hsspi_probe()
440 struct clk *clk, *pll_clk = NULL; in bcmbca_hsspi_probe() local
450 return -EINVAL; in bcmbca_hsspi_probe()
455 res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spim-ctrl"); in bcmbca_hsspi_probe()
457 return -EINVAL; in bcmbca_hsspi_probe()
462 clk = devm_clk_get(dev, "hsspi"); in bcmbca_hsspi_probe()
463 if (IS_ERR(clk)) in bcmbca_hsspi_probe()
464 return PTR_ERR(clk); in bcmbca_hsspi_probe()
466 ret = clk_prepare_enable(clk); in bcmbca_hsspi_probe()
470 rate = clk_get_rate(clk); in bcmbca_hsspi_probe()
485 ret = -EINVAL; in bcmbca_hsspi_probe()
490 host = spi_alloc_host(&pdev->dev, sizeof(*bs)); in bcmbca_hsspi_probe()
492 ret = -ENOMEM; in bcmbca_hsspi_probe()
497 bs->pdev = pdev; in bcmbca_hsspi_probe()
498 bs->clk = clk; in bcmbca_hsspi_probe()
499 bs->pll_clk = pll_clk; in bcmbca_hsspi_probe()
500 bs->regs = regs; in bcmbca_hsspi_probe()
501 bs->spim_ctrl = spim_ctrl; in bcmbca_hsspi_probe()
502 bs->speed_hz = rate; in bcmbca_hsspi_probe()
503 bs->fifo = (u8 __iomem *) (bs->regs + HSSPI_FIFO_REG(0)); in bcmbca_hsspi_probe()
504 bs->wait_mode = HSSPI_WAIT_MODE_POLLING; in bcmbca_hsspi_probe()
506 mutex_init(&bs->bus_mutex); in bcmbca_hsspi_probe()
507 mutex_init(&bs->msg_mutex); in bcmbca_hsspi_probe()
508 init_completion(&bs->done); in bcmbca_hsspi_probe()
510 host->dev.of_node = dev->of_node; in bcmbca_hsspi_probe()
511 if (!dev->of_node) in bcmbca_hsspi_probe()
512 host->bus_num = HSSPI_BUS_NUM; in bcmbca_hsspi_probe()
514 of_property_read_u32(dev->of_node, "num-cs", &num_cs); in bcmbca_hsspi_probe()
520 host->num_chipselect = num_cs; in bcmbca_hsspi_probe()
521 host->setup = bcmbca_hsspi_setup; in bcmbca_hsspi_probe()
522 host->transfer_one_message = bcmbca_hsspi_transfer_one; in bcmbca_hsspi_probe()
523 host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | in bcmbca_hsspi_probe()
525 host->bits_per_word_mask = SPI_BPW_MASK(8); in bcmbca_hsspi_probe()
526 host->auto_runtime_pm = true; in bcmbca_hsspi_probe()
531 __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); in bcmbca_hsspi_probe()
534 __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG); in bcmbca_hsspi_probe()
537 reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG); in bcmbca_hsspi_probe()
538 bs->cs_polarity = reg & GLOBAL_CTRL_CS_POLARITY_MASK; in bcmbca_hsspi_probe()
540 bs->regs + HSSPI_GLOBAL_CTRL_REG); in bcmbca_hsspi_probe()
544 pdev->name, bs); in bcmbca_hsspi_probe()
549 ret = devm_pm_runtime_enable(&pdev->dev); in bcmbca_hsspi_probe()
553 ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group); in bcmbca_hsspi_probe()
555 dev_err(&pdev->dev, "couldn't register sysfs group\n"); in bcmbca_hsspi_probe()
564 dev_info(dev, "Broadcom BCMBCA High Speed SPI Controller driver"); in bcmbca_hsspi_probe()
569 sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group); in bcmbca_hsspi_probe()
575 clk_disable_unprepare(clk); in bcmbca_hsspi_probe()
585 __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); in bcmbca_hsspi_remove()
586 clk_disable_unprepare(bs->pll_clk); in bcmbca_hsspi_remove()
587 clk_disable_unprepare(bs->clk); in bcmbca_hsspi_remove()
588 sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group); in bcmbca_hsspi_remove()
598 clk_disable_unprepare(bs->pll_clk); in bcmbca_hsspi_suspend()
599 clk_disable_unprepare(bs->clk); in bcmbca_hsspi_suspend()
610 ret = clk_prepare_enable(bs->clk); in bcmbca_hsspi_resume()
614 if (bs->pll_clk) { in bcmbca_hsspi_resume()
615 ret = clk_prepare_enable(bs->pll_clk); in bcmbca_hsspi_resume()
617 clk_disable_unprepare(bs->clk); in bcmbca_hsspi_resume()
632 { .compatible = "brcm,bcmbca-hsspi-v1.1", },
640 .name = "bcmbca-hsspi",
651 MODULE_DESCRIPTION("Broadcom BCMBCA High Speed SPI Controller driver");