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