linux/drivers/spi/spi_s3c24xx.c
<<
>>
Prefs
   1/* linux/drivers/spi/spi_s3c24xx.c
   2 *
   3 * Copyright (c) 2006 Ben Dooks
   4 * Copyright (c) 2006 Simtec Electronics
   5 *      Ben Dooks <ben@simtec.co.uk>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11*/
  12
  13#include <linux/init.h>
  14#include <linux/spinlock.h>
  15#include <linux/workqueue.h>
  16#include <linux/interrupt.h>
  17#include <linux/delay.h>
  18#include <linux/errno.h>
  19#include <linux/err.h>
  20#include <linux/clk.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/io.h>
  27#include <asm/dma.h>
  28#include <mach/hardware.h>
  29
  30#include <mach/regs-gpio.h>
  31#include <asm/plat-s3c24xx/regs-spi.h>
  32#include <mach/spi.h>
  33
  34struct s3c24xx_spi {
  35        /* bitbang has to be first */
  36        struct spi_bitbang       bitbang;
  37        struct completion        done;
  38
  39        void __iomem            *regs;
  40        int                      irq;
  41        int                      len;
  42        int                      count;
  43
  44        void                    (*set_cs)(struct s3c2410_spi_info *spi,
  45                                          int cs, int pol);
  46
  47        /* data buffers */
  48        const unsigned char     *tx;
  49        unsigned char           *rx;
  50
  51        struct clk              *clk;
  52        struct resource         *ioarea;
  53        struct spi_master       *master;
  54        struct spi_device       *curdev;
  55        struct device           *dev;
  56        struct s3c2410_spi_info *pdata;
  57};
  58
  59#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
  60#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
  61
  62static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
  63{
  64        return spi_master_get_devdata(sdev->master);
  65}
  66
  67static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
  68{
  69        s3c2410_gpio_setpin(spi->pin_cs, pol);
  70}
  71
  72static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
  73{
  74        struct s3c24xx_spi *hw = to_hw(spi);
  75        unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
  76        unsigned int spcon;
  77
  78        switch (value) {
  79        case BITBANG_CS_INACTIVE:
  80                hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
  81                break;
  82
  83        case BITBANG_CS_ACTIVE:
  84                spcon = readb(hw->regs + S3C2410_SPCON);
  85
  86                if (spi->mode & SPI_CPHA)
  87                        spcon |= S3C2410_SPCON_CPHA_FMTB;
  88                else
  89                        spcon &= ~S3C2410_SPCON_CPHA_FMTB;
  90
  91                if (spi->mode & SPI_CPOL)
  92                        spcon |= S3C2410_SPCON_CPOL_HIGH;
  93                else
  94                        spcon &= ~S3C2410_SPCON_CPOL_HIGH;
  95
  96                spcon |= S3C2410_SPCON_ENSCK;
  97
  98                /* write new configration */
  99
 100                writeb(spcon, hw->regs + S3C2410_SPCON);
 101                hw->set_cs(hw->pdata, spi->chip_select, cspol);
 102
 103                break;
 104        }
 105}
 106
 107static int s3c24xx_spi_setupxfer(struct spi_device *spi,
 108                                 struct spi_transfer *t)
 109{
 110        struct s3c24xx_spi *hw = to_hw(spi);
 111        unsigned int bpw;
 112        unsigned int hz;
 113        unsigned int div;
 114
 115        bpw = t ? t->bits_per_word : spi->bits_per_word;
 116        hz  = t ? t->speed_hz : spi->max_speed_hz;
 117
 118        if (bpw != 8) {
 119                dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
 120                return -EINVAL;
 121        }
 122
 123        div = clk_get_rate(hw->clk) / hz;
 124
 125        /* is clk = pclk / (2 * (pre+1)), or is it
 126         *    clk = (pclk * 2) / ( pre + 1) */
 127
 128        div /= 2;
 129
 130        if (div > 0)
 131                div -= 1;
 132
 133        if (div > 255)
 134                div = 255;
 135
 136        dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz);
 137        writeb(div, hw->regs + S3C2410_SPPRE);
 138
 139        spin_lock(&hw->bitbang.lock);
 140        if (!hw->bitbang.busy) {
 141                hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
 142                /* need to ndelay for 0.5 clocktick ? */
 143        }
 144        spin_unlock(&hw->bitbang.lock);
 145
 146        return 0;
 147}
 148
 149/* the spi->mode bits understood by this driver: */
 150#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
 151
 152static int s3c24xx_spi_setup(struct spi_device *spi)
 153{
 154        int ret;
 155
 156        if (!spi->bits_per_word)
 157                spi->bits_per_word = 8;
 158
 159        if (spi->mode & ~MODEBITS) {
 160                dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
 161                        spi->mode & ~MODEBITS);
 162                return -EINVAL;
 163        }
 164
 165        ret = s3c24xx_spi_setupxfer(spi, NULL);
 166        if (ret < 0) {
 167                dev_err(&spi->dev, "setupxfer returned %d\n", ret);
 168                return ret;
 169        }
 170
 171        dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
 172                __func__, spi->mode, spi->bits_per_word,
 173                spi->max_speed_hz);
 174
 175        return 0;
 176}
 177
 178static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
 179{
 180        return hw->tx ? hw->tx[count] : 0;
 181}
 182
 183static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
 184{
 185        struct s3c24xx_spi *hw = to_hw(spi);
 186
 187        dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
 188                t->tx_buf, t->rx_buf, t->len);
 189
 190        hw->tx = t->tx_buf;
 191        hw->rx = t->rx_buf;
 192        hw->len = t->len;
 193        hw->count = 0;
 194
 195        init_completion(&hw->done);
 196
 197        /* send the first byte */
 198        writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
 199
 200        wait_for_completion(&hw->done);
 201
 202        return hw->count;
 203}
 204
 205static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
 206{
 207        struct s3c24xx_spi *hw = dev;
 208        unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
 209        unsigned int count = hw->count;
 210
 211        if (spsta & S3C2410_SPSTA_DCOL) {
 212                dev_dbg(hw->dev, "data-collision\n");
 213                complete(&hw->done);
 214                goto irq_done;
 215        }
 216
 217        if (!(spsta & S3C2410_SPSTA_READY)) {
 218                dev_dbg(hw->dev, "spi not ready for tx?\n");
 219                complete(&hw->done);
 220                goto irq_done;
 221        }
 222
 223        hw->count++;
 224
 225        if (hw->rx)
 226                hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
 227
 228        count++;
 229
 230        if (count < hw->len)
 231                writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
 232        else
 233                complete(&hw->done);
 234
 235 irq_done:
 236        return IRQ_HANDLED;
 237}
 238
 239static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
 240{
 241        /* for the moment, permanently enable the clock */
 242
 243        clk_enable(hw->clk);
 244
 245        /* program defaults into the registers */
 246
 247        writeb(0xff, hw->regs + S3C2410_SPPRE);
 248        writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
 249        writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
 250
 251        if (hw->pdata && hw->pdata->gpio_setup)
 252                hw->pdata->gpio_setup(hw->pdata, 1);
 253}
 254
 255static int __init s3c24xx_spi_probe(struct platform_device *pdev)
 256{
 257        struct s3c2410_spi_info *pdata;
 258        struct s3c24xx_spi *hw;
 259        struct spi_master *master;
 260        struct resource *res;
 261        int err = 0;
 262
 263        master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
 264        if (master == NULL) {
 265                dev_err(&pdev->dev, "No memory for spi_master\n");
 266                err = -ENOMEM;
 267                goto err_nomem;
 268        }
 269
 270        hw = spi_master_get_devdata(master);
 271        memset(hw, 0, sizeof(struct s3c24xx_spi));
 272
 273        hw->master = spi_master_get(master);
 274        hw->pdata = pdata = pdev->dev.platform_data;
 275        hw->dev = &pdev->dev;
 276
 277        if (pdata == NULL) {
 278                dev_err(&pdev->dev, "No platform data supplied\n");
 279                err = -ENOENT;
 280                goto err_no_pdata;
 281        }
 282
 283        platform_set_drvdata(pdev, hw);
 284        init_completion(&hw->done);
 285
 286        /* setup the master state. */
 287
 288        master->num_chipselect = hw->pdata->num_cs;
 289        master->bus_num = pdata->bus_num;
 290
 291        /* setup the state for the bitbang driver */
 292
 293        hw->bitbang.master         = hw->master;
 294        hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
 295        hw->bitbang.chipselect     = s3c24xx_spi_chipsel;
 296        hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;
 297        hw->bitbang.master->setup  = s3c24xx_spi_setup;
 298
 299        dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
 300
 301        /* find and map our resources */
 302
 303        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 304        if (res == NULL) {
 305                dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
 306                err = -ENOENT;
 307                goto err_no_iores;
 308        }
 309
 310        hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,
 311                                        pdev->name);
 312
 313        if (hw->ioarea == NULL) {
 314                dev_err(&pdev->dev, "Cannot reserve region\n");
 315                err = -ENXIO;
 316                goto err_no_iores;
 317        }
 318
 319        hw->regs = ioremap(res->start, (res->end - res->start)+1);
 320        if (hw->regs == NULL) {
 321                dev_err(&pdev->dev, "Cannot map IO\n");
 322                err = -ENXIO;
 323                goto err_no_iomap;
 324        }
 325
 326        hw->irq = platform_get_irq(pdev, 0);
 327        if (hw->irq < 0) {
 328                dev_err(&pdev->dev, "No IRQ specified\n");
 329                err = -ENOENT;
 330                goto err_no_irq;
 331        }
 332
 333        err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
 334        if (err) {
 335                dev_err(&pdev->dev, "Cannot claim IRQ\n");
 336                goto err_no_irq;
 337        }
 338
 339        hw->clk = clk_get(&pdev->dev, "spi");
 340        if (IS_ERR(hw->clk)) {
 341                dev_err(&pdev->dev, "No clock for device\n");
 342                err = PTR_ERR(hw->clk);
 343                goto err_no_clk;
 344        }
 345
 346        s3c24xx_spi_initialsetup(hw);
 347
 348        /* setup any gpio we can */
 349
 350        if (!pdata->set_cs) {
 351                hw->set_cs = s3c24xx_spi_gpiocs;
 352
 353                s3c2410_gpio_setpin(pdata->pin_cs, 1);
 354                s3c2410_gpio_cfgpin(pdata->pin_cs, S3C2410_GPIO_OUTPUT);
 355        } else
 356                hw->set_cs = pdata->set_cs;
 357
 358        /* register our spi controller */
 359
 360        err = spi_bitbang_start(&hw->bitbang);
 361        if (err) {
 362                dev_err(&pdev->dev, "Failed to register SPI master\n");
 363                goto err_register;
 364        }
 365
 366        return 0;
 367
 368 err_register:
 369        clk_disable(hw->clk);
 370        clk_put(hw->clk);
 371
 372 err_no_clk:
 373        free_irq(hw->irq, hw);
 374
 375 err_no_irq:
 376        iounmap(hw->regs);
 377
 378 err_no_iomap:
 379        release_resource(hw->ioarea);
 380        kfree(hw->ioarea);
 381
 382 err_no_iores:
 383 err_no_pdata:
 384        spi_master_put(hw->master);;
 385
 386 err_nomem:
 387        return err;
 388}
 389
 390static int __exit s3c24xx_spi_remove(struct platform_device *dev)
 391{
 392        struct s3c24xx_spi *hw = platform_get_drvdata(dev);
 393
 394        platform_set_drvdata(dev, NULL);
 395
 396        spi_unregister_master(hw->master);
 397
 398        clk_disable(hw->clk);
 399        clk_put(hw->clk);
 400
 401        free_irq(hw->irq, hw);
 402        iounmap(hw->regs);
 403
 404        release_resource(hw->ioarea);
 405        kfree(hw->ioarea);
 406
 407        spi_master_put(hw->master);
 408        return 0;
 409}
 410
 411
 412#ifdef CONFIG_PM
 413
 414static int s3c24xx_spi_suspend(struct platform_device *pdev, pm_message_t msg)
 415{
 416        struct s3c24xx_spi *hw = platform_get_drvdata(pdev);
 417
 418        if (hw->pdata && hw->pdata->gpio_setup)
 419                hw->pdata->gpio_setup(hw->pdata, 0);
 420
 421        clk_disable(hw->clk);
 422        return 0;
 423}
 424
 425static int s3c24xx_spi_resume(struct platform_device *pdev)
 426{
 427        struct s3c24xx_spi *hw = platform_get_drvdata(pdev);
 428
 429        s3c24xx_spi_initialsetup(hw);
 430        return 0;
 431}
 432
 433#else
 434#define s3c24xx_spi_suspend NULL
 435#define s3c24xx_spi_resume  NULL
 436#endif
 437
 438MODULE_ALIAS("platform:s3c2410-spi");
 439static struct platform_driver s3c24xx_spi_driver = {
 440        .remove         = __exit_p(s3c24xx_spi_remove),
 441        .suspend        = s3c24xx_spi_suspend,
 442        .resume         = s3c24xx_spi_resume,
 443        .driver         = {
 444                .name   = "s3c2410-spi",
 445                .owner  = THIS_MODULE,
 446        },
 447};
 448
 449static int __init s3c24xx_spi_init(void)
 450{
 451        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);
 452}
 453
 454static void __exit s3c24xx_spi_exit(void)
 455{
 456        platform_driver_unregister(&s3c24xx_spi_driver);
 457}
 458
 459module_init(s3c24xx_spi_init);
 460module_exit(s3c24xx_spi_exit);
 461
 462MODULE_DESCRIPTION("S3C24XX SPI Driver");
 463MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 464MODULE_LICENSE("GPL");
 465