linux/drivers/net/dsa/b53/b53_spi.c
<<
>>
Prefs
   1/*
   2 * B53 register access through SPI
   3 *
   4 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
   5 *
   6 * Permission to use, copy, modify, and/or distribute this software for any
   7 * purpose with or without fee is hereby granted, provided that the above
   8 * copyright notice and this permission notice appear in all copies.
   9 *
  10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17 */
  18
  19#include <asm/unaligned.h>
  20
  21#include <linux/delay.h>
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/spi/spi.h>
  25#include <linux/platform_data/b53.h>
  26
  27#include "b53_priv.h"
  28
  29#define B53_SPI_DATA            0xf0
  30
  31#define B53_SPI_STATUS          0xfe
  32#define B53_SPI_CMD_SPIF        BIT(7)
  33#define B53_SPI_CMD_RACK        BIT(5)
  34
  35#define B53_SPI_CMD_READ        0x00
  36#define B53_SPI_CMD_WRITE       0x01
  37#define B53_SPI_CMD_NORMAL      0x60
  38#define B53_SPI_CMD_FAST        0x10
  39
  40#define B53_SPI_PAGE_SELECT     0xff
  41
  42static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
  43                                   unsigned int len)
  44{
  45        u8 txbuf[2];
  46
  47        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
  48        txbuf[1] = reg;
  49
  50        return spi_write_then_read(spi, txbuf, 2, val, len);
  51}
  52
  53static inline int b53_spi_clear_status(struct spi_device *spi)
  54{
  55        unsigned int i;
  56        u8 rxbuf;
  57        int ret;
  58
  59        for (i = 0; i < 10; i++) {
  60                ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
  61                if (ret)
  62                        return ret;
  63
  64                if (!(rxbuf & B53_SPI_CMD_SPIF))
  65                        break;
  66
  67                mdelay(1);
  68        }
  69
  70        if (i == 10)
  71                return -EIO;
  72
  73        return 0;
  74}
  75
  76static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
  77{
  78        u8 txbuf[3];
  79
  80        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
  81        txbuf[1] = B53_SPI_PAGE_SELECT;
  82        txbuf[2] = page;
  83
  84        return spi_write(spi, txbuf, sizeof(txbuf));
  85}
  86
  87static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
  88{
  89        int ret = b53_spi_clear_status(spi);
  90
  91        if (ret)
  92                return ret;
  93
  94        return b53_spi_set_page(spi, page);
  95}
  96
  97static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
  98{
  99        u8 rxbuf;
 100        int retry_count;
 101        int ret;
 102
 103        ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
 104        if (ret)
 105                return ret;
 106
 107        for (retry_count = 0; retry_count < 10; retry_count++) {
 108                ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
 109                if (ret)
 110                        return ret;
 111
 112                if (rxbuf & B53_SPI_CMD_RACK)
 113                        break;
 114
 115                mdelay(1);
 116        }
 117
 118        if (retry_count == 10)
 119                return -EIO;
 120
 121        return 0;
 122}
 123
 124static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
 125                        unsigned int len)
 126{
 127        struct spi_device *spi = dev->priv;
 128        int ret;
 129
 130        ret = b53_prepare_reg_access(spi, page);
 131        if (ret)
 132                return ret;
 133
 134        ret = b53_spi_prepare_reg_read(spi, reg);
 135        if (ret)
 136                return ret;
 137
 138        return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
 139}
 140
 141static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 142{
 143        return b53_spi_read(dev, page, reg, val, 1);
 144}
 145
 146static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 147{
 148        int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
 149
 150        if (!ret)
 151                *val = le16_to_cpu(*val);
 152
 153        return ret;
 154}
 155
 156static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 157{
 158        int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
 159
 160        if (!ret)
 161                *val = le32_to_cpu(*val);
 162
 163        return ret;
 164}
 165
 166static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 167{
 168        int ret;
 169
 170        *val = 0;
 171        ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
 172        if (!ret)
 173                *val = le64_to_cpu(*val);
 174
 175        return ret;
 176}
 177
 178static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 179{
 180        int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
 181
 182        if (!ret)
 183                *val = le64_to_cpu(*val);
 184
 185        return ret;
 186}
 187
 188static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 189{
 190        struct spi_device *spi = dev->priv;
 191        int ret;
 192        u8 txbuf[3];
 193
 194        ret = b53_prepare_reg_access(spi, page);
 195        if (ret)
 196                return ret;
 197
 198        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 199        txbuf[1] = reg;
 200        txbuf[2] = value;
 201
 202        return spi_write(spi, txbuf, sizeof(txbuf));
 203}
 204
 205static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
 206{
 207        struct spi_device *spi = dev->priv;
 208        int ret;
 209        u8 txbuf[4];
 210
 211        ret = b53_prepare_reg_access(spi, page);
 212        if (ret)
 213                return ret;
 214
 215        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 216        txbuf[1] = reg;
 217        put_unaligned_le16(value, &txbuf[2]);
 218
 219        return spi_write(spi, txbuf, sizeof(txbuf));
 220}
 221
 222static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
 223{
 224        struct spi_device *spi = dev->priv;
 225        int ret;
 226        u8 txbuf[6];
 227
 228        ret = b53_prepare_reg_access(spi, page);
 229        if (ret)
 230                return ret;
 231
 232        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 233        txbuf[1] = reg;
 234        put_unaligned_le32(value, &txbuf[2]);
 235
 236        return spi_write(spi, txbuf, sizeof(txbuf));
 237}
 238
 239static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
 240{
 241        struct spi_device *spi = dev->priv;
 242        int ret;
 243        u8 txbuf[10];
 244
 245        ret = b53_prepare_reg_access(spi, page);
 246        if (ret)
 247                return ret;
 248
 249        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 250        txbuf[1] = reg;
 251        put_unaligned_le64(value, &txbuf[2]);
 252
 253        return spi_write(spi, txbuf, sizeof(txbuf) - 2);
 254}
 255
 256static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
 257{
 258        struct spi_device *spi = dev->priv;
 259        int ret;
 260        u8 txbuf[10];
 261
 262        ret = b53_prepare_reg_access(spi, page);
 263        if (ret)
 264                return ret;
 265
 266        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 267        txbuf[1] = reg;
 268        put_unaligned_le64(value, &txbuf[2]);
 269
 270        return spi_write(spi, txbuf, sizeof(txbuf));
 271}
 272
 273static const struct b53_io_ops b53_spi_ops = {
 274        .read8 = b53_spi_read8,
 275        .read16 = b53_spi_read16,
 276        .read32 = b53_spi_read32,
 277        .read48 = b53_spi_read48,
 278        .read64 = b53_spi_read64,
 279        .write8 = b53_spi_write8,
 280        .write16 = b53_spi_write16,
 281        .write32 = b53_spi_write32,
 282        .write48 = b53_spi_write48,
 283        .write64 = b53_spi_write64,
 284};
 285
 286static int b53_spi_probe(struct spi_device *spi)
 287{
 288        struct b53_device *dev;
 289        int ret;
 290
 291        dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
 292        if (!dev)
 293                return -ENOMEM;
 294
 295        if (spi->dev.platform_data)
 296                dev->pdata = spi->dev.platform_data;
 297
 298        ret = b53_switch_register(dev);
 299        if (ret)
 300                return ret;
 301
 302        spi_set_drvdata(spi, dev);
 303
 304        return 0;
 305}
 306
 307static int b53_spi_remove(struct spi_device *spi)
 308{
 309        struct b53_device *dev = spi_get_drvdata(spi);
 310
 311        if (dev)
 312                b53_switch_remove(dev);
 313
 314        return 0;
 315}
 316
 317static struct spi_driver b53_spi_driver = {
 318        .driver = {
 319                .name   = "b53-switch",
 320        },
 321        .probe  = b53_spi_probe,
 322        .remove = b53_spi_remove,
 323};
 324
 325module_spi_driver(b53_spi_driver);
 326
 327MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
 328MODULE_DESCRIPTION("B53 SPI access driver");
 329MODULE_LICENSE("Dual BSD/GPL");
 330