linux/drivers/spi/spi-sh-sci.c
<<
>>
Prefs
   1/*
   2 * SH SCI SPI interface
   3 *
   4 * Copyright (c) 2008 Magnus Damm
   5 *
   6 * Based on S3C24XX GPIO based SPI driver, which is:
   7 *   Copyright (c) 2006 Ben Dooks
   8 *   Copyright (c) 2006 Simtec Electronics
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 *
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/delay.h>
  18#include <linux/spinlock.h>
  19#include <linux/platform_device.h>
  20
  21#include <linux/spi/spi.h>
  22#include <linux/spi/spi_bitbang.h>
  23#include <linux/module.h>
  24
  25#include <asm/spi.h>
  26#include <asm/io.h>
  27
  28struct sh_sci_spi {
  29        struct spi_bitbang bitbang;
  30
  31        void __iomem *membase;
  32        unsigned char val;
  33        struct sh_spi_info *info;
  34        struct platform_device *dev;
  35};
  36
  37#define SCSPTR(sp)      (sp->membase + 0x1c)
  38#define PIN_SCK         (1 << 2)
  39#define PIN_TXD         (1 << 0)
  40#define PIN_RXD         PIN_TXD
  41#define PIN_INIT        ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
  42
  43static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
  44{
  45        /*
  46         * We are the only user of SCSPTR so no locking is required.
  47         * Reading bit 2 and 0 in SCSPTR gives pin state as input.
  48         * Writing the same bits sets the output value.
  49         * This makes regular read-modify-write difficult so we
  50         * use sp->val to keep track of the latest register value.
  51         */
  52
  53        if (on)
  54                sp->val |= bits;
  55        else
  56                sp->val &= ~bits;
  57
  58        iowrite8(sp->val, SCSPTR(sp));
  59}
  60
  61static inline void setsck(struct spi_device *dev, int on)
  62{
  63        setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
  64}
  65
  66static inline void setmosi(struct spi_device *dev, int on)
  67{
  68        setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
  69}
  70
  71static inline u32 getmiso(struct spi_device *dev)
  72{
  73        struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
  74
  75        return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
  76}
  77
  78#define spidelay(x) ndelay(x)
  79
  80#include "spi-bitbang-txrx.h"
  81
  82static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
  83                                      unsigned nsecs, u32 word, u8 bits)
  84{
  85        return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
  86}
  87
  88static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
  89                                      unsigned nsecs, u32 word, u8 bits)
  90{
  91        return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
  92}
  93
  94static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
  95                                      unsigned nsecs, u32 word, u8 bits)
  96{
  97        return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
  98}
  99
 100static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
 101                                      unsigned nsecs, u32 word, u8 bits)
 102{
 103        return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, 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