linux/drivers/spi/spi-orion.c
<<
>>
Prefs
   1/*
   2 * Marvell Orion SPI controller driver
   3 *
   4 * Author: Shadi Ammouri <shadi@marvell.com>
   5 * Copyright (C) 2007-2008 Marvell Ltd.
   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#include <linux/interrupt.h>
  13#include <linux/delay.h>
  14#include <linux/platform_device.h>
  15#include <linux/err.h>
  16#include <linux/io.h>
  17#include <linux/spi/spi.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/clk.h>
  21#include <linux/sizes.h>
  22#include <asm/unaligned.h>
  23
  24#define DRIVER_NAME                     "orion_spi"
  25
  26#define ORION_NUM_CHIPSELECTS           1 /* only one slave is supported*/
  27#define ORION_SPI_WAIT_RDY_MAX_LOOP     2000 /* in usec */
  28
  29#define ORION_SPI_IF_CTRL_REG           0x00
  30#define ORION_SPI_IF_CONFIG_REG         0x04
  31#define ORION_SPI_DATA_OUT_REG          0x08
  32#define ORION_SPI_DATA_IN_REG           0x0c
  33#define ORION_SPI_INT_CAUSE_REG         0x10
  34
  35#define ORION_SPI_MODE_CPOL             (1 << 11)
  36#define ORION_SPI_MODE_CPHA             (1 << 12)
  37#define ORION_SPI_IF_8_16_BIT_MODE      (1 << 5)
  38#define ORION_SPI_CLK_PRESCALE_MASK     0x1F
  39#define ORION_SPI_MODE_MASK             (ORION_SPI_MODE_CPOL | \
  40                                         ORION_SPI_MODE_CPHA)
  41
  42struct orion_spi {
  43        struct spi_master       *master;
  44        void __iomem            *base;
  45        struct clk              *clk;
  46};
  47
  48static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
  49{
  50        return orion_spi->base + reg;
  51}
  52
  53static inline void
  54orion_spi_setbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
  55{
  56        void __iomem *reg_addr = spi_reg(orion_spi, reg);
  57        u32 val;
  58
  59        val = readl(reg_addr);
  60        val |= mask;
  61        writel(val, reg_addr);
  62}
  63
  64static inline void
  65orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
  66{
  67        void __iomem *reg_addr = spi_reg(orion_spi, reg);
  68        u32 val;
  69
  70        val = readl(reg_addr);
  71        val &= ~mask;
  72        writel(val, reg_addr);
  73}
  74
  75static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
  76{
  77        u32 tclk_hz;
  78        u32 rate;
  79        u32 prescale;
  80        u32 reg;
  81        struct orion_spi *orion_spi;
  82
  83        orion_spi = spi_master_get_devdata(spi->master);
  84
  85        tclk_hz = clk_get_rate(orion_spi->clk);
  86
  87        /*
  88         * the supported rates are: 4,6,8...30
  89         * round up as we look for equal or less speed
  90         */
  91        rate = DIV_ROUND_UP(tclk_hz, speed);
  92        rate = roundup(rate, 2);
  93
  94        /* check if requested speed is too small */
  95        if (rate > 30)
  96                return -EINVAL;
  97
  98        if (rate < 4)
  99                rate = 4;
 100
 101        /* Convert the rate to SPI clock divisor value. */
 102        prescale = 0x10 + rate/2;
 103
 104        reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
 105        reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale);
 106        writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
 107
 108        return 0;
 109}
 110
 111static void
 112orion_spi_mode_set(struct spi_device *spi)
 113{
 114        u32 reg;
 115        struct orion_spi *orion_spi;
 116
 117        orion_spi = spi_master_get_devdata(spi->master);
 118
 119        reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
 120        reg &= ~ORION_SPI_MODE_MASK;
 121        if (spi->mode & SPI_CPOL)
 122                reg |= ORION_SPI_MODE_CPOL;
 123        if (spi->mode & SPI_CPHA)
 124                reg |= ORION_SPI_MODE_CPHA;
 125        writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
 126}
 127
 128/*
 129 * called only when no transfer is active on the bus
 130 */
 131static int
 132orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 133{
 134        struct orion_spi *orion_spi;
 135        unsigned int speed = spi->max_speed_hz;
 136        unsigned int bits_per_word = spi->bits_per_word;
 137        int     rc;
 138
 139        orion_spi = spi_master_get_devdata(spi->master);
 140
 141        if ((t != NULL) && t->speed_hz)
 142                speed = t->speed_hz;
 143
 144        if ((t != NULL) && t->bits_per_word)
 145                bits_per_word = t->bits_per_word;
 146
 147        orion_spi_mode_set(spi);
 148
 149        rc = orion_spi_baudrate_set(spi, speed);
 150        if (rc)
 151                return rc;
 152
 153        if (bits_per_word == 16)
 154                orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
 155                                  ORION_SPI_IF_8_16_BIT_MODE);
 156        else
 157                orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
 158                                  ORION_SPI_IF_8_16_BIT_MODE);
 159
 160        return 0;
 161}
 162
 163static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
 164{
 165        if (enable)
 166                orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
 167        else
 168                orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
 169}
 170
 171static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi)
 172{
 173        int i;
 174
 175        for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) {
 176                if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG)))
 177                        return 1;
 178                else
 179                        udelay(1);
 180        }
 181
 182        return -1;
 183}
 184
 185static inline int
 186orion_spi_write_read_8bit(struct spi_device *spi,
 187                          const u8 **tx_buf, u8 **rx_buf)
 188{
 189        void __iomem *tx_reg, *rx_reg, *int_reg;
 190        struct orion_spi *orion_spi;
 191
 192        orion_spi = spi_master_get_devdata(spi->master);
 193        tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
 194        rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
 195        int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
 196
 197        /* clear the interrupt cause register */
 198        writel(0x0, int_reg);
 199
 200        if (tx_buf && *tx_buf)
 201                writel(*(*tx_buf)++, tx_reg);
 202        else
 203                writel(0, tx_reg);
 204
 205        if (orion_spi_wait_till_ready(orion_spi) < 0) {
 206                dev_err(&spi->dev, "TXS timed out\n");
 207                return -1;
 208        }
 209
 210        if (rx_buf && *rx_buf)
 211                *(*rx_buf)++ = readl(rx_reg);
 212
 213        return 1;
 214}
 215
 216static inline int
 217orion_spi_write_read_16bit(struct spi_device *spi,
 218                           const u16 **tx_buf, u16 **rx_buf)
 219{
 220        void __iomem *tx_reg, *rx_reg, *int_reg;
 221        struct orion_spi *orion_spi;
 222
 223        orion_spi = spi_master_get_devdata(spi->master);
 224        tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
 225        rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
 226        int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
 227
 228        /* clear the interrupt cause register */
 229        writel(0x0, int_reg);
 230
 231        if (tx_buf && *tx_buf)
 232                writel(__cpu_to_le16(get_unaligned((*tx_buf)++)), tx_reg);
 233        else
 234                writel(0, tx_reg);
 235
 236        if (orion_spi_wait_till_ready(orion_spi) < 0) {
 237                dev_err(&spi->dev, "TXS timed out\n");
 238                return -1;
 239        }
 240
 241        if (rx_buf && *rx_buf)
 242                put_unaligned(__le16_to_cpu(readl(rx_reg)), (*rx_buf)++);
 243
 244        return 1;
 245}
 246
 247static unsigned int
 248orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
 249{
 250        unsigned int count;
 251        int word_len;
 252
 253        word_len = spi->bits_per_word;
 254        count = xfer->len;
 255
 256        if (word_len == 8) {
 257                const u8 *tx = xfer->tx_buf;
 258                u8 *rx = xfer->rx_buf;
 259
 260                do {
 261                        if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0)
 262                                goto out;
 263                        count--;
 264                } while (count);
 265        } else if (word_len == 16) {
 266                const u16 *tx = xfer->tx_buf;
 267                u16 *rx = xfer->rx_buf;
 268
 269                do {
 270                        if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0)
 271                                goto out;
 272                        count -= 2;
 273                } while (count);
 274        }
 275
 276out:
 277        return xfer->len - count;
 278}
 279
 280
 281static int orion_spi_transfer_one_message(struct spi_master *master,
 282                                           struct spi_message *m)
 283{
 284        struct orion_spi *orion_spi = spi_master_get_devdata(master);
 285        struct spi_device *spi = m->spi;
 286        struct spi_transfer *t = NULL;
 287        int par_override = 0;
 288        int status = 0;
 289        int cs_active = 0;
 290
 291        /* Load defaults */
 292        status = orion_spi_setup_transfer(spi, NULL);
 293
 294        if (status < 0)
 295                goto msg_done;
 296
 297        list_for_each_entry(t, &m->transfers, transfer_list) {
 298                if (par_override || t->speed_hz || t->bits_per_word) {
 299                        par_override = 1;
 300                        status = orion_spi_setup_transfer(spi, t);
 301                        if (status < 0)
 302                                break;
 303                        if (!t->speed_hz && !t->bits_per_word)
 304                                par_override = 0;
 305                }
 306
 307                if (!cs_active) {
 308                        orion_spi_set_cs(orion_spi, 1);
 309                        cs_active = 1;
 310                }
 311
 312                if (t->len)
 313                        m->actual_length += orion_spi_write_read(spi, t);
 314
 315                if (t->delay_usecs)
 316                        udelay(t->delay_usecs);
 317
 318                if (t->cs_change) {
 319                        orion_spi_set_cs(orion_spi, 0);
 320                        cs_active = 0;
 321                }
 322        }
 323
 324msg_done:
 325        if (cs_active)
 326                orion_spi_set_cs(orion_spi, 0);
 327
 328        m->status = status;
 329        spi_finalize_current_message(master);
 330
 331        return 0;
 332}
 333
 334static int orion_spi_reset(struct orion_spi *orion_spi)
 335{
 336        /* Verify that the CS is deasserted */
 337        orion_spi_set_cs(orion_spi, 0);
 338
 339        return 0;
 340}
 341
 342static int orion_spi_probe(struct platform_device *pdev)
 343{
 344        struct spi_master *master;
 345        struct orion_spi *spi;
 346        struct resource *r;
 347        unsigned long tclk_hz;
 348        int status = 0;
 349        const u32 *iprop;
 350        int size;
 351
 352        master = spi_alloc_master(&pdev->dev, sizeof(*spi));
 353        if (master == NULL) {
 354                dev_dbg(&pdev->dev, "master allocation failed\n");
 355                return -ENOMEM;
 356        }
 357
 358        if (pdev->id != -1)
 359                master->bus_num = pdev->id;
 360        if (pdev->dev.of_node) {
 361                iprop = of_get_property(pdev->dev.of_node, "cell-index",
 362                                        &size);
 363                if (iprop && size == sizeof(*iprop))
 364                        master->bus_num = *iprop;
 365        }
 366
 367        /* we support only mode 0, and no options */
 368        master->mode_bits = SPI_CPHA | SPI_CPOL;
 369
 370        master->transfer_one_message = orion_spi_transfer_one_message;
 371        master->num_chipselect = ORION_NUM_CHIPSELECTS;
 372        master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
 373
 374        platform_set_drvdata(pdev, master);
 375
 376        spi = spi_master_get_devdata(master);
 377        spi->master = master;
 378
 379        spi->clk = devm_clk_get(&pdev->dev, NULL);
 380        if (IS_ERR(spi->clk)) {
 381                status = PTR_ERR(spi->clk);
 382                goto out;
 383        }
 384
 385        clk_prepare(spi->clk);
 386        clk_enable(spi->clk);
 387        tclk_hz = clk_get_rate(spi->clk);
 388        master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
 389        master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
 390
 391        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 392        spi->base = devm_ioremap_resource(&pdev->dev, r);
 393        if (IS_ERR(spi->base)) {
 394                status = PTR_ERR(spi->base);
 395                goto out_rel_clk;
 396        }
 397
 398        if (orion_spi_reset(spi) < 0)
 399                goto out_rel_clk;
 400
 401        master->dev.of_node = pdev->dev.of_node;
 402        status = devm_spi_register_master(&pdev->dev, master);
 403        if (status < 0)
 404                goto out_rel_clk;
 405
 406        return status;
 407
 408out_rel_clk:
 409        clk_disable_unprepare(spi->clk);
 410out:
 411        spi_master_put(master);
 412        return status;
 413}
 414
 415
 416static int orion_spi_remove(struct platform_device *pdev)
 417{
 418        struct spi_master *master;
 419        struct orion_spi *spi;
 420
 421        master = platform_get_drvdata(pdev);
 422        spi = spi_master_get_devdata(master);
 423
 424        clk_disable_unprepare(spi->clk);
 425
 426        return 0;
 427}
 428
 429MODULE_ALIAS("platform:" DRIVER_NAME);
 430
 431static const struct of_device_id orion_spi_of_match_table[] = {
 432        { .compatible = "marvell,orion-spi", },
 433        {}
 434};
 435MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
 436
 437static struct platform_driver orion_spi_driver = {
 438        .driver = {
 439                .name   = DRIVER_NAME,
 440                .owner  = THIS_MODULE,
 441                .of_match_table = of_match_ptr(orion_spi_of_match_table),
 442        },
 443        .probe          = orion_spi_probe,
 444        .remove         = orion_spi_remove,
 445};
 446
 447module_platform_driver(orion_spi_driver);
 448
 449MODULE_DESCRIPTION("Orion SPI driver");
 450MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
 451MODULE_LICENSE("GPL");
 452