linux/drivers/spi/spi-nuc900.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2009 Nuvoton technology.
   3 * Wan ZongShun <mcuos.com@gmail.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 *
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/spinlock.h>
  13#include <linux/interrupt.h>
  14#include <linux/delay.h>
  15#include <linux/errno.h>
  16#include <linux/err.h>
  17#include <linux/clk.h>
  18#include <linux/device.h>
  19#include <linux/platform_device.h>
  20#include <linux/gpio.h>
  21#include <linux/io.h>
  22#include <linux/slab.h>
  23
  24#include <linux/spi/spi.h>
  25#include <linux/spi/spi_bitbang.h>
  26
  27#include <linux/platform_data/spi-nuc900.h>
  28
  29/* usi registers offset */
  30#define USI_CNT         0x00
  31#define USI_DIV         0x04
  32#define USI_SSR         0x08
  33#define USI_RX0         0x10
  34#define USI_TX0         0x10
  35
  36/* usi register bit */
  37#define ENINT           (0x01 << 17)
  38#define ENFLG           (0x01 << 16)
  39#define SLEEP           (0x0f << 12)
  40#define TXNUM           (0x03 << 8)
  41#define TXBITLEN        (0x1f << 3)
  42#define TXNEG           (0x01 << 2)
  43#define RXNEG           (0x01 << 1)
  44#define LSB             (0x01 << 10)
  45#define SELECTLEV       (0x01 << 2)
  46#define SELECTPOL       (0x01 << 31)
  47#define SELECTSLAVE     0x01
  48#define GOBUSY          0x01
  49
  50struct nuc900_spi {
  51        struct spi_bitbang       bitbang;
  52        struct completion        done;
  53        void __iomem            *regs;
  54        int                      irq;
  55        int                      len;
  56        int                      count;
  57        const unsigned char     *tx;
  58        unsigned char           *rx;
  59        struct clk              *clk;
  60        struct spi_master       *master;
  61        struct nuc900_spi_info *pdata;
  62        spinlock_t              lock;
  63};
  64
  65static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
  66{
  67        return spi_master_get_devdata(sdev->master);
  68}
  69
  70static void nuc900_slave_select(struct spi_device *spi, unsigned int ssr)
  71{
  72        struct nuc900_spi *hw = to_hw(spi);
  73        unsigned int val;
  74        unsigned int cs = spi->mode & SPI_CS_HIGH ? 1 : 0;
  75        unsigned int cpol = spi->mode & SPI_CPOL ? 1 : 0;
  76        unsigned long flags;
  77
  78        spin_lock_irqsave(&hw->lock, flags);
  79
  80        val = __raw_readl(hw->regs + USI_SSR);
  81
  82        if (!cs)
  83                val &= ~SELECTLEV;
  84        else
  85                val |= SELECTLEV;
  86
  87        if (!ssr)
  88                val &= ~SELECTSLAVE;
  89        else
  90                val |= SELECTSLAVE;
  91
  92        __raw_writel(val, hw->regs + USI_SSR);
  93
  94        val = __raw_readl(hw->regs + USI_CNT);
  95
  96        if (!cpol)
  97                val &= ~SELECTPOL;
  98        else
  99                val |= SELECTPOL;
 100
 101        __raw_writel(val, hw->regs + USI_CNT);
 102
 103        spin_unlock_irqrestore(&hw->lock, flags);
 104}
 105
 106static void nuc900_spi_chipsel(struct spi_device *spi, int value)
 107{
 108        switch (value) {
 109        case BITBANG_CS_INACTIVE:
 110                nuc900_slave_select(spi, 0);
 111                break;
 112
 113        case BITBANG_CS_ACTIVE:
 114                nuc900_slave_select(spi, 1);
 115                break;
 116        }
 117}
 118
 119static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
 120{
 121        unsigned int val;
 122        unsigned long flags;
 123
 124        spin_lock_irqsave(&hw->lock, flags);
 125
 126        val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
 127
 128        if (txnum)
 129                val |= txnum << 0x08;
 130
 131        __raw_writel(val, hw->regs + USI_CNT);
 132
 133        spin_unlock_irqrestore(&hw->lock, flags);
 134
 135}
 136
 137static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
 138                                                        unsigned int txbitlen)
 139{
 140        unsigned int val;
 141        unsigned long flags;
 142
 143        spin_lock_irqsave(&hw->lock, flags);
 144
 145        val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
 146
 147        val |= (txbitlen << 0x03);
 148
 149        __raw_writel(val, hw->regs + USI_CNT);
 150
 151        spin_unlock_irqrestore(&hw->lock, flags);
 152}
 153
 154static void nuc900_spi_gobusy(struct nuc900_spi *hw)
 155{
 156        unsigned int val;
 157        unsigned long flags;
 158
 159        spin_lock_irqsave(&hw->lock, flags);
 160
 161        val = __raw_readl(hw->regs + USI_CNT);
 162
 163        val |= GOBUSY;
 164
 165        __raw_writel(val, hw->regs + USI_CNT);
 166
 167        spin_unlock_irqrestore(&hw->lock, flags);
 168}
 169
 170static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
 171{
 172        return hw->tx ? hw->tx[count] : 0;
 173}
 174
 175static int nuc900_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
 176{
 177        struct nuc900_spi *hw = to_hw(spi);
 178
 179        hw->tx = t->tx_buf;
 180        hw->rx = t->rx_buf;
 181        hw->len = t->len;
 182        hw->count = 0;
 183
 184        __raw_writel(hw_txbyte(hw, 0x0), hw->regs + USI_TX0);
 185
 186        nuc900_spi_gobusy(hw);
 187
 188        wait_for_completion(&hw->done);
 189
 190        return hw->count;
 191}
 192
 193static irqreturn_t nuc900_spi_irq(int irq, void *dev)
 194{
 195        struct nuc900_spi *hw = dev;
 196        unsigned int status;
 197        unsigned int count = hw->count;
 198
 199        status = __raw_readl(hw->regs + USI_CNT);
 200        __raw_writel(status, hw->regs + USI_CNT);
 201
 202        if (status & ENFLG) {
 203                hw->count++;
 204
 205                if (hw->rx)
 206                        hw->rx[count] = __raw_readl(hw->regs + USI_RX0);
 207                count++;
 208
 209                if (count < hw->len) {
 210                        __raw_writel(hw_txbyte(hw, count), hw->regs + USI_TX0);
 211                        nuc900_spi_gobusy(hw);
 212                } else {
 213                        complete(&hw->done);
 214                }
 215
 216                return IRQ_HANDLED;
 217        }
 218
 219        complete(&hw->done);
 220        return IRQ_HANDLED;
 221}
 222
 223static void nuc900_tx_edge(struct nuc900_spi *hw, unsigned int edge)
 224{
 225        unsigned int val;
 226        unsigned long flags;
 227
 228        spin_lock_irqsave(&hw->lock, flags);
 229
 230        val = __raw_readl(hw->regs + USI_CNT);
 231
 232        if (edge)
 233                val |= TXNEG;
 234        else
 235                val &= ~TXNEG;
 236        __raw_writel(val, hw->regs + USI_CNT);
 237
 238        spin_unlock_irqrestore(&hw->lock, flags);
 239}
 240
 241static void nuc900_rx_edge(struct nuc900_spi *hw, unsigned int edge)
 242{
 243        unsigned int val;
 244        unsigned long flags;
 245
 246        spin_lock_irqsave(&hw->lock, flags);
 247
 248        val = __raw_readl(hw->regs + USI_CNT);
 249
 250        if (edge)
 251                val |= RXNEG;
 252        else
 253                val &= ~RXNEG;
 254        __raw_writel(val, hw->regs + USI_CNT);
 255
 256        spin_unlock_irqrestore(&hw->lock, flags);
 257}
 258
 259static void nuc900_send_first(struct nuc900_spi *hw, unsigned int lsb)
 260{
 261        unsigned int val;
 262        unsigned long flags;
 263
 264        spin_lock_irqsave(&hw->lock, flags);
 265
 266        val = __raw_readl(hw->regs + USI_CNT);
 267
 268        if (lsb)
 269                val |= LSB;
 270        else
 271                val &= ~LSB;
 272        __raw_writel(val, hw->regs + USI_CNT);
 273
 274        spin_unlock_irqrestore(&hw->lock, flags);
 275}
 276
 277static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
 278{
 279        unsigned int val;
 280        unsigned long flags;
 281
 282        spin_lock_irqsave(&hw->lock, flags);
 283
 284        val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
 285
 286        if (sleep)
 287                val |= (sleep << 12);
 288
 289        __raw_writel(val, hw->regs + USI_CNT);
 290
 291        spin_unlock_irqrestore(&hw->lock, flags);
 292}
 293
 294static void nuc900_enable_int(struct nuc900_spi *hw)
 295{
 296        unsigned int val;
 297        unsigned long flags;
 298
 299        spin_lock_irqsave(&hw->lock, flags);
 300
 301        val = __raw_readl(hw->regs + USI_CNT);
 302
 303        val |= ENINT;
 304
 305        __raw_writel(val, hw->regs + USI_CNT);
 306
 307        spin_unlock_irqrestore(&hw->lock, flags);
 308}
 309
 310static void nuc900_set_divider(struct nuc900_spi *hw)
 311{
 312        __raw_writel(hw->pdata->divider, hw->regs + USI_DIV);
 313}
 314
 315static void nuc900_init_spi(struct nuc900_spi *hw)
 316{
 317        clk_enable(hw->clk);
 318        spin_lock_init(&hw->lock);
 319
 320        nuc900_tx_edge(hw, hw->pdata->txneg);
 321        nuc900_rx_edge(hw, hw->pdata->rxneg);
 322        nuc900_send_first(hw, hw->pdata->lsb);
 323        nuc900_set_sleep(hw, hw->pdata->sleep);
 324        nuc900_spi_setup_txbitlen(hw, hw->pdata->txbitlen);
 325        nuc900_spi_setup_txnum(hw, hw->pdata->txnum);
 326        nuc900_set_divider(hw);
 327        nuc900_enable_int(hw);
 328}
 329
 330static int nuc900_spi_probe(struct platform_device *pdev)
 331{
 332        struct nuc900_spi *hw;
 333        struct spi_master *master;
 334        struct resource *res;
 335        int err = 0;
 336
 337        master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
 338        if (master == NULL) {
 339                dev_err(&pdev->dev, "No memory for spi_master\n");
 340                return -ENOMEM;
 341        }
 342
 343        hw = spi_master_get_devdata(master);
 344        hw->master = master;
 345        hw->pdata  = dev_get_platdata(&pdev->dev);
 346
 347        if (hw->pdata == NULL) {
 348                dev_err(&pdev->dev, "No platform data supplied\n");
 349                err = -ENOENT;
 350                goto err_pdata;
 351        }
 352
 353        platform_set_drvdata(pdev, hw);
 354        init_completion(&hw->done);
 355
 356        master->mode_bits          = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 357        if (hw->pdata->lsb)
 358                master->mode_bits |= SPI_LSB_FIRST;
 359        master->num_chipselect     = hw->pdata->num_cs;
 360        master->bus_num            = hw->pdata->bus_num;
 361        hw->bitbang.master         = hw->master;
 362        hw->bitbang.chipselect     = nuc900_spi_chipsel;
 363        hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
 364
 365        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 366        hw->regs = devm_ioremap_resource(&pdev->dev, res);
 367        if (IS_ERR(hw->regs)) {
 368                err = PTR_ERR(hw->regs);
 369                goto err_pdata;
 370        }
 371
 372        hw->irq = platform_get_irq(pdev, 0);
 373        if (hw->irq < 0) {
 374                dev_err(&pdev->dev, "No IRQ specified\n");
 375                err = -ENOENT;
 376                goto err_pdata;
 377        }
 378
 379        err = devm_request_irq(&pdev->dev, hw->irq, nuc900_spi_irq, 0,
 380                                pdev->name, hw);
 381        if (err) {
 382                dev_err(&pdev->dev, "Cannot claim IRQ\n");
 383                goto err_pdata;
 384        }
 385
 386        hw->clk = devm_clk_get(&pdev->dev, "spi");
 387        if (IS_ERR(hw->clk)) {
 388                dev_err(&pdev->dev, "No clock for device\n");
 389                err = PTR_ERR(hw->clk);
 390                goto err_pdata;
 391        }
 392
 393        mfp_set_groupg(&pdev->dev, NULL);
 394        nuc900_init_spi(hw);
 395
 396        err = spi_bitbang_start(&hw->bitbang);
 397        if (err) {
 398                dev_err(&pdev->dev, "Failed to register SPI master\n");
 399                goto err_register;
 400        }
 401
 402        return 0;
 403
 404err_register:
 405        clk_disable(hw->clk);
 406err_pdata:
 407        spi_master_put(hw->master);
 408        return err;
 409}
 410
 411static int nuc900_spi_remove(struct platform_device *dev)
 412{
 413        struct nuc900_spi *hw = platform_get_drvdata(dev);
 414
 415        spi_bitbang_stop(&hw->bitbang);
 416        clk_disable(hw->clk);
 417        spi_master_put(hw->master);
 418        return 0;
 419}
 420
 421static struct platform_driver nuc900_spi_driver = {
 422        .probe          = nuc900_spi_probe,
 423        .remove         = nuc900_spi_remove,
 424        .driver         = {
 425                .name   = "nuc900-spi",
 426        },
 427};
 428module_platform_driver(nuc900_spi_driver);
 429
 430MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
 431MODULE_DESCRIPTION("nuc900 spi driver!");
 432MODULE_LICENSE("GPL");
 433MODULE_ALIAS("platform:nuc900-spi");
 434