Loading Documentation/devicetree/bindings/spi/sh-msiof.txt +16 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,22 @@ Optional properties: specifiers, one for transmission, and one for reception. - dma-names : Must contain a list of two DMA names, "tx" and "rx". - renesas,dtdl : delay sync signal (setup) in transmit mode. Must contain one of the following values: 0 (no bit delay) 50 (0.5-clock-cycle delay) 100 (1-clock-cycle delay) 150 (1.5-clock-cycle delay) 200 (2-clock-cycle delay) - renesas,syncdl : delay sync signal (hold) in transmit mode. Must contain one of the following values: 0 (no bit delay) 50 (0.5-clock-cycle delay) 100 (1-clock-cycle delay) 150 (1.5-clock-cycle delay) 200 (2-clock-cycle delay) 300 (3-clock-cycle delay) Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words Loading drivers/spi/spi-sh-msiof.c +66 −25 Original line number Diff line number Diff line Loading @@ -82,6 +82,8 @@ struct sh_msiof_spi_priv { #define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ #define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ #define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ #define MDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */ #define MDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */ #define MDR1_FLD_MASK 0x0000000c /* Frame Sync Signal Interval (0-3) */ #define MDR1_FLD_SHIFT 2 #define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ Loading Loading @@ -241,42 +243,80 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) static struct { unsigned short div; unsigned short scr; } const sh_msiof_spi_clk_table[] = { { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 }, { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 }, { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 }, { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 }, { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 }, { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 }, { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 }, { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 }, { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 }, { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 }, { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 }, unsigned short brdv; } const sh_msiof_spi_div_table[] = { { 1, SCR_BRDV_DIV_1 }, { 2, SCR_BRDV_DIV_2 }, { 4, SCR_BRDV_DIV_4 }, { 8, SCR_BRDV_DIV_8 }, { 16, SCR_BRDV_DIV_16 }, { 32, SCR_BRDV_DIV_32 }, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, unsigned long parent_rate, u32 spi_hz) { unsigned long div = 1024; u32 brps, scr; size_t k; if (!WARN_ON(!spi_hz || !parent_rate)) div = DIV_ROUND_UP(parent_rate, spi_hz); /* TODO: make more fine grained */ for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_clk_table); k++) { if (sh_msiof_spi_clk_table[k].div >= div) for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); if (brps <= 32) /* max of brdv is 32 */ break; } k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1); sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); sh_msiof_write(p, TSCR, scr); if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); sh_msiof_write(p, RSCR, scr); } static u32 sh_msiof_get_delay_bit(u32 dtdl_or_syncdl) { /* * DTDL/SYNCDL bit : p->info->dtdl or p->info->syncdl * b'000 : 0 * b'001 : 100 * b'010 : 200 * b'011 (SYNCDL only) : 300 * b'101 : 50 * b'110 : 150 */ if (dtdl_or_syncdl % 100) return dtdl_or_syncdl / 100 + 5; else return dtdl_or_syncdl / 100; } static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p) { u32 val; if (!p->info) return 0; /* check if DTDL and SYNCDL is allowed value */ if (p->info->dtdl > 200 || p->info->syncdl > 300) { dev_warn(&p->pdev->dev, "DTDL or SYNCDL is too large\n"); return 0; } /* check if the sum of DTDL and SYNCDL becomes an integer value */ if ((p->info->dtdl + p->info->syncdl) % 100) { dev_warn(&p->pdev->dev, "the sum of DTDL/SYNCDL is not good\n"); return 0; } val = sh_msiof_get_delay_bit(p->info->dtdl) << MDR1_DTDL_SHIFT; val |= sh_msiof_get_delay_bit(p->info->syncdl) << MDR1_SYNCDL_SHIFT; return val; } static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, Loading @@ -296,6 +336,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { /* These bits are reserved if RX needs TX */ Loading Loading @@ -501,7 +542,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi) gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); pm_runtime_put_sync(&p->pdev->dev); pm_runtime_put(&p->pdev->dev); return 0; } Loading Loading @@ -595,8 +636,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, } /* wait for tx fifo to be emptied / rx fifo to be filled */ ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { if (!wait_for_completion_timeout(&p->done, HZ)) { dev_err(&p->pdev->dev, "PIO timeout\n"); ret = -ETIMEDOUT; goto stop_reset; Loading Loading @@ -706,8 +746,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, } /* wait for tx fifo to be emptied / rx fifo to be filled */ ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { if (!wait_for_completion_timeout(&p->done, HZ)) { dev_err(&p->pdev->dev, "DMA timeout\n"); ret = -ETIMEDOUT; goto stop_reset; Loading Loading @@ -957,6 +996,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) &info->tx_fifo_override); of_property_read_u32(np, "renesas,rx-fifo-size", &info->rx_fifo_override); of_property_read_u32(np, "renesas,dtdl", &info->dtdl); of_property_read_u32(np, "renesas,syncdl", &info->syncdl); info->num_chipselect = num_cs; Loading include/linux/spi/sh_msiof.h +2 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ struct sh_msiof_spi_info { u16 num_chipselect; unsigned int dma_tx_id; unsigned int dma_rx_id; u32 dtdl; u32 syncdl; }; #endif /* __SPI_SH_MSIOF_H__ */ Loading
Documentation/devicetree/bindings/spi/sh-msiof.txt +16 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,22 @@ Optional properties: specifiers, one for transmission, and one for reception. - dma-names : Must contain a list of two DMA names, "tx" and "rx". - renesas,dtdl : delay sync signal (setup) in transmit mode. Must contain one of the following values: 0 (no bit delay) 50 (0.5-clock-cycle delay) 100 (1-clock-cycle delay) 150 (1.5-clock-cycle delay) 200 (2-clock-cycle delay) - renesas,syncdl : delay sync signal (hold) in transmit mode. Must contain one of the following values: 0 (no bit delay) 50 (0.5-clock-cycle delay) 100 (1-clock-cycle delay) 150 (1.5-clock-cycle delay) 200 (2-clock-cycle delay) 300 (3-clock-cycle delay) Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words Loading
drivers/spi/spi-sh-msiof.c +66 −25 Original line number Diff line number Diff line Loading @@ -82,6 +82,8 @@ struct sh_msiof_spi_priv { #define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ #define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ #define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ #define MDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */ #define MDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */ #define MDR1_FLD_MASK 0x0000000c /* Frame Sync Signal Interval (0-3) */ #define MDR1_FLD_SHIFT 2 #define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ Loading Loading @@ -241,42 +243,80 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) static struct { unsigned short div; unsigned short scr; } const sh_msiof_spi_clk_table[] = { { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 }, { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 }, { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 }, { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 }, { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 }, { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 }, { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 }, { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 }, { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 }, { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 }, { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 }, unsigned short brdv; } const sh_msiof_spi_div_table[] = { { 1, SCR_BRDV_DIV_1 }, { 2, SCR_BRDV_DIV_2 }, { 4, SCR_BRDV_DIV_4 }, { 8, SCR_BRDV_DIV_8 }, { 16, SCR_BRDV_DIV_16 }, { 32, SCR_BRDV_DIV_32 }, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, unsigned long parent_rate, u32 spi_hz) { unsigned long div = 1024; u32 brps, scr; size_t k; if (!WARN_ON(!spi_hz || !parent_rate)) div = DIV_ROUND_UP(parent_rate, spi_hz); /* TODO: make more fine grained */ for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_clk_table); k++) { if (sh_msiof_spi_clk_table[k].div >= div) for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); if (brps <= 32) /* max of brdv is 32 */ break; } k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1); sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); sh_msiof_write(p, TSCR, scr); if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); sh_msiof_write(p, RSCR, scr); } static u32 sh_msiof_get_delay_bit(u32 dtdl_or_syncdl) { /* * DTDL/SYNCDL bit : p->info->dtdl or p->info->syncdl * b'000 : 0 * b'001 : 100 * b'010 : 200 * b'011 (SYNCDL only) : 300 * b'101 : 50 * b'110 : 150 */ if (dtdl_or_syncdl % 100) return dtdl_or_syncdl / 100 + 5; else return dtdl_or_syncdl / 100; } static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p) { u32 val; if (!p->info) return 0; /* check if DTDL and SYNCDL is allowed value */ if (p->info->dtdl > 200 || p->info->syncdl > 300) { dev_warn(&p->pdev->dev, "DTDL or SYNCDL is too large\n"); return 0; } /* check if the sum of DTDL and SYNCDL becomes an integer value */ if ((p->info->dtdl + p->info->syncdl) % 100) { dev_warn(&p->pdev->dev, "the sum of DTDL/SYNCDL is not good\n"); return 0; } val = sh_msiof_get_delay_bit(p->info->dtdl) << MDR1_DTDL_SHIFT; val |= sh_msiof_get_delay_bit(p->info->syncdl) << MDR1_SYNCDL_SHIFT; return val; } static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, Loading @@ -296,6 +336,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { /* These bits are reserved if RX needs TX */ Loading Loading @@ -501,7 +542,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi) gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); pm_runtime_put_sync(&p->pdev->dev); pm_runtime_put(&p->pdev->dev); return 0; } Loading Loading @@ -595,8 +636,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, } /* wait for tx fifo to be emptied / rx fifo to be filled */ ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { if (!wait_for_completion_timeout(&p->done, HZ)) { dev_err(&p->pdev->dev, "PIO timeout\n"); ret = -ETIMEDOUT; goto stop_reset; Loading Loading @@ -706,8 +746,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, } /* wait for tx fifo to be emptied / rx fifo to be filled */ ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { if (!wait_for_completion_timeout(&p->done, HZ)) { dev_err(&p->pdev->dev, "DMA timeout\n"); ret = -ETIMEDOUT; goto stop_reset; Loading Loading @@ -957,6 +996,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) &info->tx_fifo_override); of_property_read_u32(np, "renesas,rx-fifo-size", &info->rx_fifo_override); of_property_read_u32(np, "renesas,dtdl", &info->dtdl); of_property_read_u32(np, "renesas,syncdl", &info->syncdl); info->num_chipselect = num_cs; Loading
include/linux/spi/sh_msiof.h +2 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ struct sh_msiof_spi_info { u16 num_chipselect; unsigned int dma_tx_id; unsigned int dma_rx_id; u32 dtdl; u32 syncdl; }; #endif /* __SPI_SH_MSIOF_H__ */