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