Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Altera SPI driver
0004  *
0005  * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
0006  *
0007  * Based on spi_s3c24xx.c, which is:
0008  * Copyright (c) 2006 Ben Dooks
0009  * Copyright (c) 2006 Simtec Electronics
0010  *  Ben Dooks <ben@simtec.co.uk>
0011  */
0012 
0013 #include <linux/errno.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/spi/altera.h>
0017 #include <linux/spi/spi.h>
0018 #include <linux/io.h>
0019 #include <linux/of.h>
0020 
0021 #define DRV_NAME "spi_altera"
0022 
0023 #define ALTERA_SPI_RXDATA   0
0024 #define ALTERA_SPI_TXDATA   4
0025 #define ALTERA_SPI_STATUS   8
0026 #define ALTERA_SPI_CONTROL  12
0027 #define ALTERA_SPI_SLAVE_SEL    20
0028 
0029 #define ALTERA_SPI_STATUS_ROE_MSK   0x8
0030 #define ALTERA_SPI_STATUS_TOE_MSK   0x10
0031 #define ALTERA_SPI_STATUS_TMT_MSK   0x20
0032 #define ALTERA_SPI_STATUS_TRDY_MSK  0x40
0033 #define ALTERA_SPI_STATUS_RRDY_MSK  0x80
0034 #define ALTERA_SPI_STATUS_E_MSK     0x100
0035 
0036 #define ALTERA_SPI_CONTROL_IROE_MSK 0x8
0037 #define ALTERA_SPI_CONTROL_ITOE_MSK 0x10
0038 #define ALTERA_SPI_CONTROL_ITRDY_MSK    0x40
0039 #define ALTERA_SPI_CONTROL_IRRDY_MSK    0x80
0040 #define ALTERA_SPI_CONTROL_IE_MSK   0x100
0041 #define ALTERA_SPI_CONTROL_SSO_MSK  0x400
0042 
0043 static int altr_spi_writel(struct altera_spi *hw, unsigned int reg,
0044                unsigned int val)
0045 {
0046     int ret;
0047 
0048     ret = regmap_write(hw->regmap, hw->regoff + reg, val);
0049     if (ret)
0050         dev_err(hw->dev, "fail to write reg 0x%x val 0x%x: %d\n",
0051             reg, val, ret);
0052 
0053     return ret;
0054 }
0055 
0056 static int altr_spi_readl(struct altera_spi *hw, unsigned int reg,
0057               unsigned int *val)
0058 {
0059     int ret;
0060 
0061     ret = regmap_read(hw->regmap, hw->regoff + reg, val);
0062     if (ret)
0063         dev_err(hw->dev, "fail to read reg 0x%x: %d\n", reg, ret);
0064 
0065     return ret;
0066 }
0067 
0068 static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
0069 {
0070     return spi_master_get_devdata(sdev->master);
0071 }
0072 
0073 static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
0074 {
0075     struct altera_spi *hw = altera_spi_to_hw(spi);
0076 
0077     if (is_high) {
0078         hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
0079         altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
0080         altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0);
0081     } else {
0082         altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL,
0083                 BIT(spi->chip_select));
0084         hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
0085         altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
0086     }
0087 }
0088 
0089 static void altera_spi_tx_word(struct altera_spi *hw)
0090 {
0091     unsigned int txd = 0;
0092 
0093     if (hw->tx) {
0094         switch (hw->bytes_per_word) {
0095         case 1:
0096             txd = hw->tx[hw->count];
0097             break;
0098         case 2:
0099             txd = (hw->tx[hw->count * 2]
0100                 | (hw->tx[hw->count * 2 + 1] << 8));
0101             break;
0102         case 4:
0103             txd = (hw->tx[hw->count * 4]
0104                 | (hw->tx[hw->count * 4 + 1] << 8)
0105                 | (hw->tx[hw->count * 4 + 2] << 16)
0106                 | (hw->tx[hw->count * 4 + 3] << 24));
0107             break;
0108 
0109         }
0110     }
0111 
0112     altr_spi_writel(hw, ALTERA_SPI_TXDATA, txd);
0113 }
0114 
0115 static void altera_spi_rx_word(struct altera_spi *hw)
0116 {
0117     unsigned int rxd;
0118 
0119     altr_spi_readl(hw, ALTERA_SPI_RXDATA, &rxd);
0120     if (hw->rx) {
0121         switch (hw->bytes_per_word) {
0122         case 1:
0123             hw->rx[hw->count] = rxd;
0124             break;
0125         case 2:
0126             hw->rx[hw->count * 2] = rxd;
0127             hw->rx[hw->count * 2 + 1] = rxd >> 8;
0128             break;
0129         case 4:
0130             hw->rx[hw->count * 4] = rxd;
0131             hw->rx[hw->count * 4 + 1] = rxd >> 8;
0132             hw->rx[hw->count * 4 + 2] = rxd >> 16;
0133             hw->rx[hw->count * 4 + 3] = rxd >> 24;
0134             break;
0135 
0136         }
0137     }
0138 
0139     hw->count++;
0140 }
0141 
0142 static int altera_spi_txrx(struct spi_master *master,
0143     struct spi_device *spi, struct spi_transfer *t)
0144 {
0145     struct altera_spi *hw = spi_master_get_devdata(master);
0146     u32 val;
0147 
0148     hw->tx = t->tx_buf;
0149     hw->rx = t->rx_buf;
0150     hw->count = 0;
0151     hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
0152     hw->len = t->len / hw->bytes_per_word;
0153 
0154     if (hw->irq >= 0) {
0155         /* enable receive interrupt */
0156         hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
0157         altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
0158 
0159         /* send the first byte */
0160         altera_spi_tx_word(hw);
0161 
0162         return 1;
0163     }
0164 
0165     while (hw->count < hw->len) {
0166         altera_spi_tx_word(hw);
0167 
0168         for (;;) {
0169             altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);
0170             if (val & ALTERA_SPI_STATUS_RRDY_MSK)
0171                 break;
0172 
0173             cpu_relax();
0174         }
0175 
0176         altera_spi_rx_word(hw);
0177     }
0178     spi_finalize_current_transfer(master);
0179 
0180     return 0;
0181 }
0182 
0183 irqreturn_t altera_spi_irq(int irq, void *dev)
0184 {
0185     struct spi_master *master = dev;
0186     struct altera_spi *hw = spi_master_get_devdata(master);
0187 
0188     altera_spi_rx_word(hw);
0189 
0190     if (hw->count < hw->len) {
0191         altera_spi_tx_word(hw);
0192     } else {
0193         /* disable receive interrupt */
0194         hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
0195         altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
0196 
0197         spi_finalize_current_transfer(master);
0198     }
0199 
0200     return IRQ_HANDLED;
0201 }
0202 EXPORT_SYMBOL_GPL(altera_spi_irq);
0203 
0204 void altera_spi_init_master(struct spi_master *master)
0205 {
0206     struct altera_spi *hw = spi_master_get_devdata(master);
0207     u32 val;
0208 
0209     master->transfer_one = altera_spi_txrx;
0210     master->set_cs = altera_spi_set_cs;
0211 
0212     /* program defaults into the registers */
0213     hw->imr = 0;        /* disable spi interrupts */
0214     altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
0215     altr_spi_writel(hw, ALTERA_SPI_STATUS, 0);  /* clear status reg */
0216     altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);
0217     if (val & ALTERA_SPI_STATUS_RRDY_MSK)
0218         altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */
0219 }
0220 EXPORT_SYMBOL_GPL(altera_spi_init_master);
0221 
0222 MODULE_LICENSE("GPL");