root/drivers/spi/spi-oc-tiny.c

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

DEFINITIONS

This source file includes following definitions.
  1. tiny_spi_to_hw
  2. tiny_spi_baud
  3. tiny_spi_chipselect
  4. tiny_spi_setup_transfer
  5. tiny_spi_setup
  6. tiny_spi_wait_txr
  7. tiny_spi_wait_txe
  8. tiny_spi_txrx_bufs
  9. tiny_spi_irq
  10. tiny_spi_of_probe
  11. tiny_spi_of_probe
  12. tiny_spi_probe
  13. tiny_spi_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * OpenCores tiny SPI master driver
   4  *
   5  * http://opencores.org/project,tiny_spi
   6  *
   7  * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
   8  *
   9  * Based on spi_s3c24xx.c, which is:
  10  * Copyright (c) 2006 Ben Dooks
  11  * Copyright (c) 2006 Simtec Electronics
  12  *      Ben Dooks <ben@simtec.co.uk>
  13  */
  14 
  15 #include <linux/interrupt.h>
  16 #include <linux/errno.h>
  17 #include <linux/module.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/spi/spi.h>
  20 #include <linux/spi/spi_bitbang.h>
  21 #include <linux/spi/spi_oc_tiny.h>
  22 #include <linux/io.h>
  23 #include <linux/gpio.h>
  24 #include <linux/of.h>
  25 
  26 #define DRV_NAME "spi_oc_tiny"
  27 
  28 #define TINY_SPI_RXDATA 0
  29 #define TINY_SPI_TXDATA 4
  30 #define TINY_SPI_STATUS 8
  31 #define TINY_SPI_CONTROL 12
  32 #define TINY_SPI_BAUD 16
  33 
  34 #define TINY_SPI_STATUS_TXE 0x1
  35 #define TINY_SPI_STATUS_TXR 0x2
  36 
  37 struct tiny_spi {
  38         /* bitbang has to be first */
  39         struct spi_bitbang bitbang;
  40         struct completion done;
  41 
  42         void __iomem *base;
  43         int irq;
  44         unsigned int freq;
  45         unsigned int baudwidth;
  46         unsigned int baud;
  47         unsigned int speed_hz;
  48         unsigned int mode;
  49         unsigned int len;
  50         unsigned int txc, rxc;
  51         const u8 *txp;
  52         u8 *rxp;
  53         int gpio_cs_count;
  54         int *gpio_cs;
  55 };
  56 
  57 static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev)
  58 {
  59         return spi_master_get_devdata(sdev->master);
  60 }
  61 
  62 static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz)
  63 {
  64         struct tiny_spi *hw = tiny_spi_to_hw(spi);
  65 
  66         return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1;
  67 }
  68 
  69 static void tiny_spi_chipselect(struct spi_device *spi, int is_active)
  70 {
  71         struct tiny_spi *hw = tiny_spi_to_hw(spi);
  72 
  73         if (hw->gpio_cs_count > 0) {
  74                 gpio_set_value(hw->gpio_cs[spi->chip_select],
  75                         (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
  76         }
  77 }
  78 
  79 static int tiny_spi_setup_transfer(struct spi_device *spi,
  80                                    struct spi_transfer *t)
  81 {
  82         struct tiny_spi *hw = tiny_spi_to_hw(spi);
  83         unsigned int baud = hw->baud;
  84 
  85         if (t) {
  86                 if (t->speed_hz && t->speed_hz != hw->speed_hz)
  87                         baud = tiny_spi_baud(spi, t->speed_hz);
  88         }
  89         writel(baud, hw->base + TINY_SPI_BAUD);
  90         writel(hw->mode, hw->base + TINY_SPI_CONTROL);
  91         return 0;
  92 }
  93 
  94 static int tiny_spi_setup(struct spi_device *spi)
  95 {
  96         struct tiny_spi *hw = tiny_spi_to_hw(spi);
  97 
  98         if (spi->max_speed_hz != hw->speed_hz) {
  99                 hw->speed_hz = spi->max_speed_hz;
 100                 hw->baud = tiny_spi_baud(spi, hw->speed_hz);
 101         }
 102         hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA);
 103         return 0;
 104 }
 105 
 106 static inline void tiny_spi_wait_txr(struct tiny_spi *hw)
 107 {
 108         while (!(readb(hw->base + TINY_SPI_STATUS) &
 109                  TINY_SPI_STATUS_TXR))
 110                 cpu_relax();
 111 }
 112 
 113 static inline void tiny_spi_wait_txe(struct tiny_spi *hw)
 114 {
 115         while (!(readb(hw->base + TINY_SPI_STATUS) &
 116                  TINY_SPI_STATUS_TXE))
 117                 cpu_relax();
 118 }
 119 
 120 static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
 121 {
 122         struct tiny_spi *hw = tiny_spi_to_hw(spi);
 123         const u8 *txp = t->tx_buf;
 124         u8 *rxp = t->rx_buf;
 125         unsigned int i;
 126 
 127         if (hw->irq >= 0) {
 128                 /* use interrupt driven data transfer */
 129                 hw->len = t->len;
 130                 hw->txp = t->tx_buf;
 131                 hw->rxp = t->rx_buf;
 132                 hw->txc = 0;
 133                 hw->rxc = 0;
 134 
 135                 /* send the first byte */
 136                 if (t->len > 1) {
 137                         writeb(hw->txp ? *hw->txp++ : 0,
 138                                hw->base + TINY_SPI_TXDATA);
 139                         hw->txc++;
 140                         writeb(hw->txp ? *hw->txp++ : 0,
 141                                hw->base + TINY_SPI_TXDATA);
 142                         hw->txc++;
 143                         writeb(TINY_SPI_STATUS_TXR, hw->base + TINY_SPI_STATUS);
 144                 } else {
 145                         writeb(hw->txp ? *hw->txp++ : 0,
 146                                hw->base + TINY_SPI_TXDATA);
 147                         hw->txc++;
 148                         writeb(TINY_SPI_STATUS_TXE, hw->base + TINY_SPI_STATUS);
 149                 }
 150 
 151                 wait_for_completion(&hw->done);
 152         } else {
 153                 /* we need to tighten the transfer loop */
 154                 writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
 155                 for (i = 1; i < t->len; i++) {
 156                         writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA);
 157 
 158                         if (rxp || (i != t->len - 1))
 159                                 tiny_spi_wait_txr(hw);
 160                         if (rxp)
 161                                 *rxp++ = readb(hw->base + TINY_SPI_TXDATA);
 162                 }
 163                 tiny_spi_wait_txe(hw);
 164                 if (rxp)
 165                         *rxp++ = readb(hw->base + TINY_SPI_RXDATA);
 166         }
 167 
 168         return t->len;
 169 }
 170 
 171 static irqreturn_t tiny_spi_irq(int irq, void *dev)
 172 {
 173         struct tiny_spi *hw = dev;
 174 
 175         writeb(0, hw->base + TINY_SPI_STATUS);
 176         if (hw->rxc + 1 == hw->len) {
 177                 if (hw->rxp)
 178                         *hw->rxp++ = readb(hw->base + TINY_SPI_RXDATA);
 179                 hw->rxc++;
 180                 complete(&hw->done);
 181         } else {
 182                 if (hw->rxp)
 183                         *hw->rxp++ = readb(hw->base + TINY_SPI_TXDATA);
 184                 hw->rxc++;
 185                 if (hw->txc < hw->len) {
 186                         writeb(hw->txp ? *hw->txp++ : 0,
 187                                hw->base + TINY_SPI_TXDATA);
 188                         hw->txc++;
 189                         writeb(TINY_SPI_STATUS_TXR,
 190                                hw->base + TINY_SPI_STATUS);
 191                 } else {
 192                         writeb(TINY_SPI_STATUS_TXE,
 193                                hw->base + TINY_SPI_STATUS);
 194                 }
 195         }
 196         return IRQ_HANDLED;
 197 }
 198 
 199 #ifdef CONFIG_OF
 200 #include <linux/of_gpio.h>
 201 
 202 static int tiny_spi_of_probe(struct platform_device *pdev)
 203 {
 204         struct tiny_spi *hw = platform_get_drvdata(pdev);
 205         struct device_node *np = pdev->dev.of_node;
 206         unsigned int i;
 207         u32 val;
 208 
 209         if (!np)
 210                 return 0;
 211         hw->gpio_cs_count = of_gpio_count(np);
 212         if (hw->gpio_cs_count > 0) {
 213                 hw->gpio_cs = devm_kcalloc(&pdev->dev,
 214                                 hw->gpio_cs_count, sizeof(unsigned int),
 215                                 GFP_KERNEL);
 216                 if (!hw->gpio_cs)
 217                         return -ENOMEM;
 218         }
 219         for (i = 0; i < hw->gpio_cs_count; i++) {
 220                 hw->gpio_cs[i] = of_get_gpio_flags(np, i, NULL);
 221                 if (hw->gpio_cs[i] < 0)
 222                         return -ENODEV;
 223         }
 224         hw->bitbang.master->dev.of_node = pdev->dev.of_node;
 225         if (!of_property_read_u32(np, "clock-frequency", &val))
 226                 hw->freq = val;
 227         if (!of_property_read_u32(np, "baud-width", &val))
 228                 hw->baudwidth = val;
 229         return 0;
 230 }
 231 #else /* !CONFIG_OF */
 232 static int tiny_spi_of_probe(struct platform_device *pdev)
 233 {
 234         return 0;
 235 }
 236 #endif /* CONFIG_OF */
 237 
 238 static int tiny_spi_probe(struct platform_device *pdev)
 239 {
 240         struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
 241         struct tiny_spi *hw;
 242         struct spi_master *master;
 243         unsigned int i;
 244         int err = -ENODEV;
 245 
 246         master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi));
 247         if (!master)
 248                 return err;
 249 
 250         /* setup the master state. */
 251         master->bus_num = pdev->id;
 252         master->num_chipselect = 255;
 253         master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 254         master->setup = tiny_spi_setup;
 255 
 256         hw = spi_master_get_devdata(master);
 257         platform_set_drvdata(pdev, hw);
 258 
 259         /* setup the state for the bitbang driver */
 260         hw->bitbang.master = master;
 261         hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
 262         hw->bitbang.chipselect = tiny_spi_chipselect;
 263         hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
 264 
 265         /* find and map our resources */
 266         hw->base = devm_platform_ioremap_resource(pdev, 0);
 267         if (IS_ERR(hw->base)) {
 268                 err = PTR_ERR(hw->base);
 269                 goto exit;
 270         }
 271         /* irq is optional */
 272         hw->irq = platform_get_irq(pdev, 0);
 273         if (hw->irq >= 0) {
 274                 init_completion(&hw->done);
 275                 err = devm_request_irq(&pdev->dev, hw->irq, tiny_spi_irq, 0,
 276                                        pdev->name, hw);
 277                 if (err)
 278                         goto exit;
 279         }
 280         /* find platform data */
 281         if (platp) {
 282                 hw->gpio_cs_count = platp->gpio_cs_count;
 283                 hw->gpio_cs = platp->gpio_cs;
 284                 if (platp->gpio_cs_count && !platp->gpio_cs) {
 285                         err = -EBUSY;
 286                         goto exit;
 287                 }
 288                 hw->freq = platp->freq;
 289                 hw->baudwidth = platp->baudwidth;
 290         } else {
 291                 err = tiny_spi_of_probe(pdev);
 292                 if (err)
 293                         goto exit;
 294         }
 295         for (i = 0; i < hw->gpio_cs_count; i++) {
 296                 err = gpio_request(hw->gpio_cs[i], dev_name(&pdev->dev));
 297                 if (err)
 298                         goto exit_gpio;
 299                 gpio_direction_output(hw->gpio_cs[i], 1);
 300         }
 301         hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count);
 302 
 303         /* register our spi controller */
 304         err = spi_bitbang_start(&hw->bitbang);
 305         if (err)
 306                 goto exit;
 307         dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
 308 
 309         return 0;
 310 
 311 exit_gpio:
 312         while (i-- > 0)
 313                 gpio_free(hw->gpio_cs[i]);
 314 exit:
 315         spi_master_put(master);
 316         return err;
 317 }
 318 
 319 static int tiny_spi_remove(struct platform_device *pdev)
 320 {
 321         struct tiny_spi *hw = platform_get_drvdata(pdev);
 322         struct spi_master *master = hw->bitbang.master;
 323         unsigned int i;
 324 
 325         spi_bitbang_stop(&hw->bitbang);
 326         for (i = 0; i < hw->gpio_cs_count; i++)
 327                 gpio_free(hw->gpio_cs[i]);
 328         spi_master_put(master);
 329         return 0;
 330 }
 331 
 332 #ifdef CONFIG_OF
 333 static const struct of_device_id tiny_spi_match[] = {
 334         { .compatible = "opencores,tiny-spi-rtlsvn2", },
 335         {},
 336 };
 337 MODULE_DEVICE_TABLE(of, tiny_spi_match);
 338 #endif /* CONFIG_OF */
 339 
 340 static struct platform_driver tiny_spi_driver = {
 341         .probe = tiny_spi_probe,
 342         .remove = tiny_spi_remove,
 343         .driver = {
 344                 .name = DRV_NAME,
 345                 .pm = NULL,
 346                 .of_match_table = of_match_ptr(tiny_spi_match),
 347         },
 348 };
 349 module_platform_driver(tiny_spi_driver);
 350 
 351 MODULE_DESCRIPTION("OpenCores tiny SPI driver");
 352 MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
 353 MODULE_LICENSE("GPL");
 354 MODULE_ALIAS("platform:" DRV_NAME);

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