diff options
Diffstat (limited to 'drivers/spi/spi-mt7621.c')
| -rw-r--r-- | drivers/spi/spi-mt7621.c | 147 |
1 files changed, 72 insertions, 75 deletions
diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c index c4cc8e2f85e2..3770b8e096a4 100644 --- a/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c @@ -14,7 +14,9 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_device.h> +#include <linux/platform_device.h> #include <linux/reset.h> #include <linux/spi/spi.h> @@ -50,8 +52,10 @@ #define MT7621_CPOL BIT(4) #define MT7621_LSB_FIRST BIT(3) +#define MT7621_NATIVE_CS_COUNT 2 + struct mt7621_spi { - struct spi_controller *master; + struct spi_controller *host; void __iomem *base; unsigned int sys_freq; unsigned int speed; @@ -60,7 +64,7 @@ struct mt7621_spi { static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) { - return spi_controller_get_devdata(spi->master); + return spi_controller_get_devdata(spi->controller); } static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg) @@ -73,26 +77,27 @@ static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val) iowrite32(val, rs->base + reg); } -static void mt7621_spi_set_cs(struct spi_device *spi, int enable) +static void mt7621_spi_set_native_cs(struct spi_device *spi, bool enable) { struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); - int cs = spi->chip_select; + int cs = spi_get_chipselect(spi, 0); + bool active = spi->mode & SPI_CS_HIGH ? enable : !enable; u32 polar = 0; - u32 master; + u32 host; /* * Select SPI device 7, enable "more buffer mode" and disable * full-duplex (only half-duplex really works on this chip * reliably) */ - master = mt7621_spi_read(rs, MT7621_SPI_MASTER); - master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE; - master &= ~MASTER_FULL_DUPLEX; - mt7621_spi_write(rs, MT7621_SPI_MASTER, master); + host = mt7621_spi_read(rs, MT7621_SPI_MASTER); + host |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE; + host &= ~MASTER_FULL_DUPLEX; + mt7621_spi_write(rs, MT7621_SPI_MASTER, host); rs->pending_write = 0; - if (enable) + if (active) polar = BIT(cs); mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); } @@ -152,6 +157,23 @@ static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs) return -ETIMEDOUT; } +static int mt7621_spi_prepare_message(struct spi_controller *host, + struct spi_message *m) +{ + struct mt7621_spi *rs = spi_controller_get_devdata(host); + struct spi_device *spi = m->spi; + unsigned int speed = spi->max_speed_hz; + struct spi_transfer *t = NULL; + + mt7621_spi_wait_till_ready(rs); + + list_for_each_entry(t, &m->transfers, transfer_list) + if (t->speed_hz < speed) + speed = t->speed_hz; + + return mt7621_spi_prepare(spi, speed); +} + static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, int rx_len, u8 *buf) { @@ -241,59 +263,30 @@ static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs, } rs->pending_write = len; + mt7621_spi_flush(rs); } -static int mt7621_spi_transfer_one_message(struct spi_controller *master, - struct spi_message *m) +static int mt7621_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) { - struct mt7621_spi *rs = spi_controller_get_devdata(master); - struct spi_device *spi = m->spi; - unsigned int speed = spi->max_speed_hz; - struct spi_transfer *t = NULL; - int status = 0; - - mt7621_spi_wait_till_ready(rs); - - list_for_each_entry(t, &m->transfers, transfer_list) - if (t->speed_hz < speed) - speed = t->speed_hz; - - if (mt7621_spi_prepare(spi, speed)) { - status = -EIO; - goto msg_done; + struct mt7621_spi *rs = spi_controller_get_devdata(host); + + if ((t->rx_buf) && (t->tx_buf)) { + /* + * This controller will shift some extra data out + * of spi_opcode if (mosi_bit_cnt > 0) && + * (cmd_bit_cnt == 0). So the claimed full-duplex + * support is broken since we have no way to read + * the MISO value during that bit. + */ + return -EIO; + } else if (t->rx_buf) { + mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); + } else if (t->tx_buf) { + mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); } - /* Assert CS */ - mt7621_spi_set_cs(spi, 1); - - m->actual_length = 0; - list_for_each_entry(t, &m->transfers, transfer_list) { - if ((t->rx_buf) && (t->tx_buf)) { - /* - * This controller will shift some extra data out - * of spi_opcode if (mosi_bit_cnt > 0) && - * (cmd_bit_cnt == 0). So the claimed full-duplex - * support is broken since we have no way to read - * the MISO value during that bit. - */ - status = -EIO; - goto msg_done; - } else if (t->rx_buf) { - mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); - } else if (t->tx_buf) { - mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); - } - m->actual_length += t->len; - } - - /* Flush data and deassert CS */ - mt7621_spi_flush(rs); - mt7621_spi_set_cs(spi, 0); - -msg_done: - m->status = status; - spi_finalize_current_message(master); - return 0; } @@ -323,7 +316,7 @@ MODULE_DEVICE_TABLE(of, mt7621_spi_match); static int mt7621_spi_probe(struct platform_device *pdev) { const struct of_device_id *match; - struct spi_controller *master; + struct spi_controller *host; struct mt7621_spi *rs; void __iomem *base; struct clk *clk; @@ -342,25 +335,29 @@ static int mt7621_spi_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(clk), "unable to get SYS clock\n"); - master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs)); - if (!master) { - dev_info(&pdev->dev, "master allocation failed\n"); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*rs)); + if (!host) { + dev_info(&pdev->dev, "host allocation failed\n"); return -ENOMEM; } - master->mode_bits = SPI_LSB_FIRST; - master->flags = SPI_CONTROLLER_HALF_DUPLEX; - master->setup = mt7621_spi_setup; - master->transfer_one_message = mt7621_spi_transfer_one_message; - master->bits_per_word_mask = SPI_BPW_MASK(8); - master->dev.of_node = pdev->dev.of_node; - master->num_chipselect = 2; - - dev_set_drvdata(&pdev->dev, master); - - rs = spi_controller_get_devdata(master); + host->mode_bits = SPI_LSB_FIRST; + host->flags = SPI_CONTROLLER_HALF_DUPLEX; + host->setup = mt7621_spi_setup; + host->prepare_message = mt7621_spi_prepare_message; + host->set_cs = mt7621_spi_set_native_cs; + host->transfer_one = mt7621_spi_transfer_one; + host->bits_per_word_mask = SPI_BPW_MASK(8); + host->dev.of_node = pdev->dev.of_node; + host->max_native_cs = MT7621_NATIVE_CS_COUNT; + host->num_chipselect = MT7621_NATIVE_CS_COUNT; + host->use_gpio_descriptors = true; + + dev_set_drvdata(&pdev->dev, host); + + rs = spi_controller_get_devdata(host); rs->base = base; - rs->master = master; + rs->host = host; rs->sys_freq = clk_get_rate(clk); rs->pending_write = 0; dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); @@ -371,7 +368,7 @@ static int mt7621_spi_probe(struct platform_device *pdev) return ret; } - return devm_spi_register_controller(&pdev->dev, master); + return devm_spi_register_controller(&pdev->dev, host); } MODULE_ALIAS("platform:" DRIVER_NAME); |
