Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * SH SCI SPI interface
0004  *
0005  * Copyright (c) 2008 Magnus Damm
0006  *
0007  * Based on S3C24XX GPIO based SPI driver, which is:
0008  *   Copyright (c) 2006 Ben Dooks
0009  *   Copyright (c) 2006 Simtec Electronics
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/delay.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/platform_device.h>
0016 
0017 #include <linux/spi/spi.h>
0018 #include <linux/spi/spi_bitbang.h>
0019 #include <linux/module.h>
0020 
0021 #include <asm/spi.h>
0022 #include <asm/io.h>
0023 
0024 struct sh_sci_spi {
0025     struct spi_bitbang bitbang;
0026 
0027     void __iomem *membase;
0028     unsigned char val;
0029     struct sh_spi_info *info;
0030     struct platform_device *dev;
0031 };
0032 
0033 #define SCSPTR(sp)  (sp->membase + 0x1c)
0034 #define PIN_SCK     (1 << 2)
0035 #define PIN_TXD     (1 << 0)
0036 #define PIN_RXD     PIN_TXD
0037 #define PIN_INIT    ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
0038 
0039 static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
0040 {
0041     /*
0042      * We are the only user of SCSPTR so no locking is required.
0043      * Reading bit 2 and 0 in SCSPTR gives pin state as input.
0044      * Writing the same bits sets the output value.
0045      * This makes regular read-modify-write difficult so we
0046      * use sp->val to keep track of the latest register value.
0047      */
0048 
0049     if (on)
0050         sp->val |= bits;
0051     else
0052         sp->val &= ~bits;
0053 
0054     iowrite8(sp->val, SCSPTR(sp));
0055 }
0056 
0057 static inline void setsck(struct spi_device *dev, int on)
0058 {
0059     setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
0060 }
0061 
0062 static inline void setmosi(struct spi_device *dev, int on)
0063 {
0064     setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
0065 }
0066 
0067 static inline u32 getmiso(struct spi_device *dev)
0068 {
0069     struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
0070 
0071     return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
0072 }
0073 
0074 #define spidelay(x) ndelay(x)
0075 
0076 #include "spi-bitbang-txrx.h"
0077 
0078 static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
0079                  unsigned nsecs, u32 word, u8 bits,
0080                  unsigned flags)
0081 {
0082     return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
0083 }
0084 
0085 static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
0086                  unsigned nsecs, u32 word, u8 bits,
0087                  unsigned flags)
0088 {
0089     return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
0090 }
0091 
0092 static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
0093                  unsigned nsecs, u32 word, u8 bits,
0094                  unsigned flags)
0095 {
0096     return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
0097 }
0098 
0099 static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
0100                  unsigned nsecs, u32 word, u8 bits,
0101                  unsigned flags)
0102 {
0103     return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
0104 }
0105 
0106 static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
0107 {
0108     struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
0109 
0110     if (sp->info->chip_select)
0111         (sp->info->chip_select)(sp->info, dev->chip_select, value);
0112 }
0113 
0114 static int sh_sci_spi_probe(struct platform_device *dev)
0115 {
0116     struct resource *r;
0117     struct spi_master *master;
0118     struct sh_sci_spi *sp;
0119     int ret;
0120 
0121     master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
0122     if (master == NULL) {
0123         dev_err(&dev->dev, "failed to allocate spi master\n");
0124         ret = -ENOMEM;
0125         goto err0;
0126     }
0127 
0128     sp = spi_master_get_devdata(master);
0129 
0130     platform_set_drvdata(dev, sp);
0131     sp->info = dev_get_platdata(&dev->dev);
0132     if (!sp->info) {
0133         dev_err(&dev->dev, "platform data is missing\n");
0134         ret = -ENOENT;
0135         goto err1;
0136     }
0137 
0138     /* setup spi bitbang adaptor */
0139     sp->bitbang.master = master;
0140     sp->bitbang.master->bus_num = sp->info->bus_num;
0141     sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
0142     sp->bitbang.chipselect = sh_sci_spi_chipselect;
0143 
0144     sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
0145     sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
0146     sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
0147     sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
0148 
0149     r = platform_get_resource(dev, IORESOURCE_MEM, 0);
0150     if (r == NULL) {
0151         ret = -ENOENT;
0152         goto err1;
0153     }
0154     sp->membase = ioremap(r->start, resource_size(r));
0155     if (!sp->membase) {
0156         ret = -ENXIO;
0157         goto err1;
0158     }
0159     sp->val = ioread8(SCSPTR(sp));
0160     setbits(sp, PIN_INIT, 1);
0161 
0162     ret = spi_bitbang_start(&sp->bitbang);
0163     if (!ret)
0164         return 0;
0165 
0166     setbits(sp, PIN_INIT, 0);
0167     iounmap(sp->membase);
0168  err1:
0169     spi_master_put(sp->bitbang.master);
0170  err0:
0171     return ret;
0172 }
0173 
0174 static int sh_sci_spi_remove(struct platform_device *dev)
0175 {
0176     struct sh_sci_spi *sp = platform_get_drvdata(dev);
0177 
0178     spi_bitbang_stop(&sp->bitbang);
0179     setbits(sp, PIN_INIT, 0);
0180     iounmap(sp->membase);
0181     spi_master_put(sp->bitbang.master);
0182     return 0;
0183 }
0184 
0185 static struct platform_driver sh_sci_spi_drv = {
0186     .probe      = sh_sci_spi_probe,
0187     .remove     = sh_sci_spi_remove,
0188     .driver     = {
0189         .name   = "spi_sh_sci",
0190     },
0191 };
0192 module_platform_driver(sh_sci_spi_drv);
0193 
0194 MODULE_DESCRIPTION("SH SCI SPI Driver");
0195 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
0196 MODULE_LICENSE("GPL");
0197 MODULE_ALIAS("platform:spi_sh_sci");