linux/drivers/spi/spi-sh-sci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * SH SCI SPI interface
   4 *
   5 * Copyright (c) 2008 Magnus Damm
   6 *
   7 * Based on S3C24XX GPIO based SPI driver, which is:
   8 *   Copyright (c) 2006 Ben Dooks
   9 *   Copyright (c) 2006 Simtec Electronics
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/delay.h>
  14#include <linux/spinlock.h>
  15#include <linux/platform_device.h>
  16
  17#include <linux/spi/spi.h>
  18#include <linux/spi/spi_bitbang.h>
  19#include <linux/module.h>
  20
  21#include <asm/spi.h>
  22#include <asm/io.h>
  23
  24struct sh_sci_spi {
  25        struct spi_bitbang bitbang;
  26
  27        void __iomem *membase;
  28        unsigned char val;
  29        struct sh_spi_info *info;
  30        struct platform_device *dev;
  31};
  32
  33#define SCSPTR(sp)      (sp->membase + 0x1c)
  34#define PIN_SCK         (1 << 2)
  35#define PIN_TXD         (1 << 0)
  36#define PIN_RXD         PIN_TXD
  37#define PIN_INIT        ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
  38
  39static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
  40{
  41        /*
  42         * We are the only user of SCSPTR so no locking is required.
  43         * Reading bit 2 and 0 in SCSPTR gives pin state as input.
  44         * Writing the same bits sets the output value.
  45         * This makes regular read-modify-write difficult so we
  46         * use sp->val to keep track of the latest register value.
  47         */
  48
  49        if (on)
  50                sp->val |= bits;
  51        else
  52                sp->val &= ~bits;
  53
  54        iowrite8(sp->val, SCSPTR(sp));
  55}
  56
  57static inline void setsck(struct spi_device *dev, int on)
  58{
  59        setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
  60}
  61
  62static inline void setmosi(struct spi_device *dev, int on)
  63{
  64        setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
  65}
  66
  67static inline u32 getmiso(struct spi_device *dev)
  68{
  69        struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
  70
  71        return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
  72}
  73
  74#define spidelay(x) ndelay(x)
  75
  76#include "spi-bitbang-txrx.h"
  77
  78static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
  79                                 unsigned nsecs, u32 word, u8 bits,
  80                                 unsigned flags)
  81{
  82        return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
  83}
  84
  85static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
  86                                 unsigned nsecs, u32 word, u8 bits,
  87                                 unsigned flags)
  88{
  89        return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
  90}
  91
  92static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
  93                                 unsigned nsecs, u32 word, u8 bits,
  94                                 unsigned flags)
  95{
  96        return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
  97}
  98
  99static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
 100                                 unsigned nsecs, u32 word, u8 bits,
 101                                 unsigned flags)
 102{
 103        return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
 104}
 105
 106static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
 107{
 108        struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
 109
 110        if (sp->info->chip_select)
 111                (sp->info->chip_select)(sp->info, dev->chip_select, value);
 112}
 113
 114static int sh_sci_spi_probe(struct platform_device *dev)
 115{
 116        struct resource *r;
 117        struct spi_master *master;
 118        struct sh_sci_spi *sp;
 119        int ret;
 120
 121        master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
 122        if (master == NULL) {
 123                dev_err(&dev->dev, "failed to allocate spi master\n");
 124                ret = -ENOMEM;
 125                goto err0;
 126        }
 127
 128        sp = spi_master_get_devdata(master);
 129
 130        platform_set_drvdata(dev, sp);
 131        sp->info = dev_get_platdata(&dev->dev);
 132        if (!sp->info) {
 133                dev_err(&dev->dev, "platform data is missing\n");
 134                ret = -ENOENT;
 135                goto err1;
 136        }
 137
 138        /* setup spi bitbang adaptor */
 139        sp->bitbang.master = master;
 140        sp->bitbang.master->bus_num = sp->info->bus_num;
 141        sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
 142        sp->bitbang.chipselect = sh_sci_spi_chipselect;
 143
 144        sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
 145        sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
 146        sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
 147        sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
 148
 149        r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 150        if (r == NULL) {
 151                ret = -ENOENT;
 152                goto err1;
 153        }
 154        sp->membase = ioremap(r->start, resource_size(r));
 155        if (!sp->membase) {
 156                ret = -ENXIO;
 157                goto err1;
 158        }
 159        sp->val = ioread8(SCSPTR(sp));
 160        setbits(sp, PIN_INIT, 1);
 161
 162        ret = spi_bitbang_start(&sp->bitbang);
 163        if (!ret)
 164                return 0;
 165
 166        setbits(sp, PIN_INIT, 0);
 167        iounmap(sp->membase);
 168 err1:
 169        spi_master_put(sp->bitbang.master);
 170 err0:
 171        return ret;
 172}
 173
 174static int sh_sci_spi_remove(struct platform_device *dev)
 175{
 176        struct sh_sci_spi *sp = platform_get_drvdata(dev);
 177
 178        spi_bitbang_stop(&sp->bitbang);
 179        setbits(sp, PIN_INIT, 0);
 180        iounmap(sp->membase);
 181        spi_master_put(sp->bitbang.master);
 182        return 0;
 183}
 184
 185static struct platform_driver sh_sci_spi_drv = {
 186        .probe          = sh_sci_spi_probe,
 187        .remove         = sh_sci_spi_remove,
 188        .driver         = {
 189                .name   = "spi_sh_sci",
 190        },
 191};
 192module_platform_driver(sh_sci_spi_drv);
 193
 194MODULE_DESCRIPTION("SH SCI SPI Driver");
 195MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
 196MODULE_LICENSE("GPL");
 197MODULE_ALIAS("platform:spi_sh_sci");
 198