root/drivers/spi/spi-altera.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. altera_spi_to_hw
  2. altera_spi_set_cs
  3. altera_spi_tx_word
  4. altera_spi_rx_word
  5. altera_spi_txrx
  6. altera_spi_irq
  7. altera_spi_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Altera SPI driver
   4  *
   5  * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
   6  *
   7  * Based on spi_s3c24xx.c, which is:
   8  * Copyright (c) 2006 Ben Dooks
   9  * Copyright (c) 2006 Simtec Electronics
  10  *      Ben Dooks <ben@simtec.co.uk>
  11  */
  12 
  13 #include <linux/interrupt.h>
  14 #include <linux/errno.h>
  15 #include <linux/module.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/spi/spi.h>
  18 #include <linux/io.h>
  19 #include <linux/of.h>
  20 
  21 #define DRV_NAME "spi_altera"
  22 
  23 #define ALTERA_SPI_RXDATA       0
  24 #define ALTERA_SPI_TXDATA       4
  25 #define ALTERA_SPI_STATUS       8
  26 #define ALTERA_SPI_CONTROL      12
  27 #define ALTERA_SPI_SLAVE_SEL    20
  28 
  29 #define ALTERA_SPI_STATUS_ROE_MSK       0x8
  30 #define ALTERA_SPI_STATUS_TOE_MSK       0x10
  31 #define ALTERA_SPI_STATUS_TMT_MSK       0x20
  32 #define ALTERA_SPI_STATUS_TRDY_MSK      0x40
  33 #define ALTERA_SPI_STATUS_RRDY_MSK      0x80
  34 #define ALTERA_SPI_STATUS_E_MSK         0x100
  35 
  36 #define ALTERA_SPI_CONTROL_IROE_MSK     0x8
  37 #define ALTERA_SPI_CONTROL_ITOE_MSK     0x10
  38 #define ALTERA_SPI_CONTROL_ITRDY_MSK    0x40
  39 #define ALTERA_SPI_CONTROL_IRRDY_MSK    0x80
  40 #define ALTERA_SPI_CONTROL_IE_MSK       0x100
  41 #define ALTERA_SPI_CONTROL_SSO_MSK      0x400
  42 
  43 struct altera_spi {
  44         void __iomem *base;
  45         int irq;
  46         int len;
  47         int count;
  48         int bytes_per_word;
  49         unsigned long imr;
  50 
  51         /* data buffers */
  52         const unsigned char *tx;
  53         unsigned char *rx;
  54 };
  55 
  56 static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
  57 {
  58         return spi_master_get_devdata(sdev->master);
  59 }
  60 
  61 static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
  62 {
  63         struct altera_spi *hw = altera_spi_to_hw(spi);
  64 
  65         if (is_high) {
  66                 hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
  67                 writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
  68                 writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
  69         } else {
  70                 writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL);
  71                 hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
  72                 writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
  73         }
  74 }
  75 
  76 static void altera_spi_tx_word(struct altera_spi *hw)
  77 {
  78         unsigned int txd = 0;
  79 
  80         if (hw->tx) {
  81                 switch (hw->bytes_per_word) {
  82                 case 1:
  83                         txd = hw->tx[hw->count];
  84                         break;
  85                 case 2:
  86                         txd = (hw->tx[hw->count * 2]
  87                                 | (hw->tx[hw->count * 2 + 1] << 8));
  88                         break;
  89                 }
  90         }
  91 
  92         writel(txd, hw->base + ALTERA_SPI_TXDATA);
  93 }
  94 
  95 static void altera_spi_rx_word(struct altera_spi *hw)
  96 {
  97         unsigned int rxd;
  98 
  99         rxd = readl(hw->base + ALTERA_SPI_RXDATA);
 100         if (hw->rx) {
 101                 switch (hw->bytes_per_word) {
 102                 case 1:
 103                         hw->rx[hw->count] = rxd;
 104                         break;
 105                 case 2:
 106                         hw->rx[hw->count * 2] = rxd;
 107                         hw->rx[hw->count * 2 + 1] = rxd >> 8;
 108                         break;
 109                 }
 110         }
 111 
 112         hw->count++;
 113 }
 114 
 115 static int altera_spi_txrx(struct spi_master *master,
 116         struct spi_device *spi, struct spi_transfer *t)
 117 {
 118         struct altera_spi *hw = spi_master_get_devdata(master);
 119 
 120         hw->tx = t->tx_buf;
 121         hw->rx = t->rx_buf;
 122         hw->count = 0;
 123         hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
 124         hw->len = t->len / hw->bytes_per_word;
 125 
 126         if (hw->irq >= 0) {
 127                 /* enable receive interrupt */
 128                 hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
 129                 writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 130 
 131                 /* send the first byte */
 132                 altera_spi_tx_word(hw);
 133         } else {
 134                 while (hw->count < hw->len) {
 135                         altera_spi_tx_word(hw);
 136 
 137                         while (!(readl(hw->base + ALTERA_SPI_STATUS) &
 138                                  ALTERA_SPI_STATUS_RRDY_MSK))
 139                                 cpu_relax();
 140 
 141                         altera_spi_rx_word(hw);
 142                 }
 143                 spi_finalize_current_transfer(master);
 144         }
 145 
 146         return t->len;
 147 }
 148 
 149 static irqreturn_t altera_spi_irq(int irq, void *dev)
 150 {
 151         struct spi_master *master = dev;
 152         struct altera_spi *hw = spi_master_get_devdata(master);
 153 
 154         altera_spi_rx_word(hw);
 155 
 156         if (hw->count < hw->len) {
 157                 altera_spi_tx_word(hw);
 158         } else {
 159                 /* disable receive interrupt */
 160                 hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
 161                 writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 162 
 163                 spi_finalize_current_transfer(master);
 164         }
 165 
 166         return IRQ_HANDLED;
 167 }
 168 
 169 static int altera_spi_probe(struct platform_device *pdev)
 170 {
 171         struct altera_spi *hw;
 172         struct spi_master *master;
 173         int err = -ENODEV;
 174 
 175         master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
 176         if (!master)
 177                 return err;
 178 
 179         /* setup the master state. */
 180         master->bus_num = pdev->id;
 181         master->num_chipselect = 16;
 182         master->mode_bits = SPI_CS_HIGH;
 183         master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
 184         master->dev.of_node = pdev->dev.of_node;
 185         master->transfer_one = altera_spi_txrx;
 186         master->set_cs = altera_spi_set_cs;
 187 
 188         hw = spi_master_get_devdata(master);
 189 
 190         /* find and map our resources */
 191         hw->base = devm_platform_ioremap_resource(pdev, 0);
 192         if (IS_ERR(hw->base)) {
 193                 err = PTR_ERR(hw->base);
 194                 goto exit;
 195         }
 196         /* program defaults into the registers */
 197         hw->imr = 0;            /* disable spi interrupts */
 198         writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 199         writel(0, hw->base + ALTERA_SPI_STATUS);        /* clear status reg */
 200         if (readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)
 201                 readl(hw->base + ALTERA_SPI_RXDATA);    /* flush rxdata */
 202         /* irq is optional */
 203         hw->irq = platform_get_irq(pdev, 0);
 204         if (hw->irq >= 0) {
 205                 err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
 206                                        pdev->name, master);
 207                 if (err)
 208                         goto exit;
 209         }
 210 
 211         err = devm_spi_register_master(&pdev->dev, master);
 212         if (err)
 213                 goto exit;
 214         dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
 215 
 216         return 0;
 217 exit:
 218         spi_master_put(master);
 219         return err;
 220 }
 221 
 222 #ifdef CONFIG_OF
 223 static const struct of_device_id altera_spi_match[] = {
 224         { .compatible = "ALTR,spi-1.0", },
 225         { .compatible = "altr,spi-1.0", },
 226         {},
 227 };
 228 MODULE_DEVICE_TABLE(of, altera_spi_match);
 229 #endif /* CONFIG_OF */
 230 
 231 static struct platform_driver altera_spi_driver = {
 232         .probe = altera_spi_probe,
 233         .driver = {
 234                 .name = DRV_NAME,
 235                 .pm = NULL,
 236                 .of_match_table = of_match_ptr(altera_spi_match),
 237         },
 238 };
 239 module_platform_driver(altera_spi_driver);
 240 
 241 MODULE_DESCRIPTION("Altera SPI driver");
 242 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
 243 MODULE_LICENSE("GPL");
 244 MODULE_ALIAS("platform:" DRV_NAME);

/* [<][>][^][v][top][bottom][index][help] */