|
15 | 15 |
|
16 | 16 | #include <linux/clk.h> |
17 | 17 | #include <linux/dmaengine.h> |
| 18 | +#include <linux/gpio.h> |
18 | 19 | #include <linux/module.h> |
19 | 20 | #include <linux/of.h> |
20 | 21 | #include <linux/platform_device.h> |
|
24 | 25 |
|
25 | 26 | #define DRIVER_NAME "rockchip-spi" |
26 | 27 |
|
| 28 | +#define ROCKCHIP_SPI_CLR_BITS(reg, bits) \ |
| 29 | + writel_relaxed(readl_relaxed(reg) & ~(bits), reg) |
| 30 | +#define ROCKCHIP_SPI_SET_BITS(reg, bits) \ |
| 31 | + writel_relaxed(readl_relaxed(reg) | (bits), reg) |
| 32 | + |
27 | 33 | /* SPI register offsets */ |
28 | 34 | #define ROCKCHIP_SPI_CTRLR0 0x0000 |
29 | 35 | #define ROCKCHIP_SPI_CTRLR1 0x0004 |
|
144 | 150 | /* max sclk of driver strength 4mA */ |
145 | 151 | #define IO_DRIVER_4MA_MAX_SCLK_OUT 24000000 |
146 | 152 |
|
| 153 | +#define ROCKCHIP_SPI_MAX_CS_NUM 4 |
| 154 | + |
147 | 155 | enum rockchip_ssi_type { |
148 | 156 | SSI_MOTO_SPI = 0, |
149 | 157 | SSI_TI_SSP, |
@@ -194,6 +202,10 @@ struct rockchip_spi { |
194 | 202 | struct rockchip_spi_dma_data dma_rx; |
195 | 203 | struct rockchip_spi_dma_data dma_tx; |
196 | 204 | struct pinctrl_state *high_speed_state; |
| 205 | + |
| 206 | + bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; |
| 207 | + |
| 208 | + bool gpio_requested; |
197 | 209 | }; |
198 | 210 |
|
199 | 211 | static inline void spi_enable_chip(struct rockchip_spi *rs, int enable) |
@@ -259,37 +271,33 @@ static inline u32 rx_max(struct rockchip_spi *rs) |
259 | 271 |
|
260 | 272 | static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) |
261 | 273 | { |
262 | | - u32 ser; |
263 | 274 | struct spi_master *master = spi->master; |
264 | 275 | struct rockchip_spi *rs = spi_master_get_devdata(master); |
| 276 | + bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable; |
265 | 277 |
|
266 | | - pm_runtime_get_sync(rs->dev); |
| 278 | + /* Return immediately for no-op */ |
| 279 | + if (cs_asserted == rs->cs_asserted[spi->chip_select]) |
| 280 | + return; |
267 | 281 |
|
268 | | - ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK; |
| 282 | + if (cs_asserted) { |
| 283 | + /* Keep things powered as long as CS is asserted */ |
| 284 | + pm_runtime_get_sync(rs->dev); |
269 | 285 |
|
270 | | - /* |
271 | | - * drivers/spi/spi.c: |
272 | | - * static void spi_set_cs(struct spi_device *spi, bool enable) |
273 | | - * { |
274 | | - * if (spi->mode & SPI_CS_HIGH) |
275 | | - * enable = !enable; |
276 | | - * |
277 | | - * if (spi->cs_gpio >= 0) |
278 | | - * gpio_set_value(spi->cs_gpio, !enable); |
279 | | - * else if (spi->master->set_cs) |
280 | | - * spi->master->set_cs(spi, !enable); |
281 | | - * } |
282 | | - * |
283 | | - * Note: enable(rockchip_spi_set_cs) = !enable(spi_set_cs) |
284 | | - */ |
285 | | - if (!enable) |
286 | | - ser |= 1 << spi->chip_select; |
287 | | - else |
288 | | - ser &= ~(1 << spi->chip_select); |
| 286 | + if (gpio_is_valid(spi->cs_gpio)) |
| 287 | + ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); |
| 288 | + else |
| 289 | + ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); |
| 290 | + } else { |
| 291 | + if (gpio_is_valid(spi->cs_gpio)) |
| 292 | + ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); |
| 293 | + else |
| 294 | + ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); |
289 | 295 |
|
290 | | - writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER); |
| 296 | + /* Drop reference from when we first asserted CS */ |
| 297 | + pm_runtime_put(rs->dev); |
| 298 | + } |
291 | 299 |
|
292 | | - pm_runtime_put_sync(rs->dev); |
| 300 | + rs->cs_asserted[spi->chip_select] = cs_asserted; |
293 | 301 | } |
294 | 302 |
|
295 | 303 | static int rockchip_spi_prepare_message(struct spi_master *master, |
@@ -678,6 +686,49 @@ static bool rockchip_spi_can_dma(struct spi_master *master, |
678 | 686 | return (xfer->len > rs->fifo_len); |
679 | 687 | } |
680 | 688 |
|
| 689 | +static int rockchip_spi_setup(struct spi_device *spi) |
| 690 | +{ |
| 691 | + |
| 692 | + int ret = -EINVAL; |
| 693 | + struct spi_master *master = spi->master; |
| 694 | + struct rockchip_spi *rs = spi_master_get_devdata(master); |
| 695 | + |
| 696 | + if (spi->cs_gpio == -ENOENT) |
| 697 | + return 0; |
| 698 | + |
| 699 | + if (!rs->gpio_requested && gpio_is_valid(spi->cs_gpio)) { |
| 700 | + ret = gpio_request_one(spi->cs_gpio, |
| 701 | + (spi->mode & SPI_CS_HIGH) ? |
| 702 | + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, |
| 703 | + dev_name(&spi->dev)); |
| 704 | + if (ret) |
| 705 | + dev_err(&spi->dev, "can't request chipselect gpio %d\n", |
| 706 | + spi->cs_gpio); |
| 707 | + else |
| 708 | + rs->gpio_requested = true; |
| 709 | + } else { |
| 710 | + if (gpio_is_valid(spi->cs_gpio)) { |
| 711 | + int mode = ((spi->mode & SPI_CS_HIGH) ? 0 : 1); |
| 712 | + |
| 713 | + ret = gpio_direction_output(spi->cs_gpio, mode); |
| 714 | + if (ret) |
| 715 | + dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", |
| 716 | + spi->cs_gpio, ret); |
| 717 | + } |
| 718 | + } |
| 719 | + |
| 720 | + return ret; |
| 721 | +} |
| 722 | + |
| 723 | +static void rockchip_spi_cleanup(struct spi_device *spi) |
| 724 | +{ |
| 725 | + struct spi_master *master = spi->master; |
| 726 | + struct rockchip_spi *rs = spi_master_get_devdata(master); |
| 727 | + |
| 728 | + if (rs->gpio_requested) |
| 729 | + gpio_free(spi->cs_gpio); |
| 730 | +} |
| 731 | + |
681 | 732 | static int rockchip_spi_probe(struct platform_device *pdev) |
682 | 733 | { |
683 | 734 | int ret = 0; |
@@ -759,6 +810,8 @@ static int rockchip_spi_probe(struct platform_device *pdev) |
759 | 810 | master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8); |
760 | 811 |
|
761 | 812 | master->set_cs = rockchip_spi_set_cs; |
| 813 | + master->setup = rockchip_spi_setup; |
| 814 | + master->cleanup = rockchip_spi_cleanup; |
762 | 815 | master->prepare_message = rockchip_spi_prepare_message; |
763 | 816 | master->unprepare_message = rockchip_spi_unprepare_message; |
764 | 817 | master->transfer_one = rockchip_spi_transfer_one; |
|
0 commit comments