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        __le16 value;
 149        int ret;
 150
 151        ret = b53_spi_read(dev, page, reg, (u8 *)&value, 2);
 152
 153        if (!ret)
 154                *val = le16_to_cpu(value);
 155
 156        return ret;
 157}
 158
 159static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 160{
 161        __le32 value;
 162        int ret;
 163
 164        ret = b53_spi_read(dev, page, reg, (u8 *)&value, 4);
 165
 166        if (!ret)
 167                *val = le32_to_cpu(value);
 168
 169        return ret;
 170}
 171
 172static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 173{
 174        __le64 value;
 175        int ret;
 176
 177        *val = 0;
 178        ret = b53_spi_read(dev, page, reg, (u8 *)&value, 6);
 179        if (!ret)
 180                *val = le64_to_cpu(value);
 181
 182        return ret;
 183}
 184
 185static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 186{
 187        __le64 value;
 188        int ret;
 189
 190        ret = b53_spi_read(dev, page, reg, (u8 *)&value, 8);
 191
 192        if (!ret)
 193                *val = le64_to_cpu(value);
 194
 195        return ret;
 196}
 197
 198static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 199{
 200        struct spi_device *spi = dev->priv;
 201        int ret;
 202        u8 txbuf[3];
 203
 204        ret = b53_prepare_reg_access(spi, page);
 205        if (ret)
 206                return ret;
 207
 208        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 209        txbuf[1] = reg;
 210        txbuf[2] = value;
 211
 212        return spi_write(spi, txbuf, sizeof(txbuf));
 213}
 214
 215static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
 216{
 217        struct spi_device *spi = dev->priv;
 218        int ret;
 219        u8 txbuf[4];
 220
 221        ret = b53_prepare_reg_access(spi, page);
 222        if (ret)
 223                return ret;
 224
 225        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 226        txbuf[1] = reg;
 227        put_unaligned_le16(value, &txbuf[2]);
 228
 229        return spi_write(spi, txbuf, sizeof(txbuf));
 230}
 231
 232static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
 233{
 234        struct spi_device *spi = dev->priv;
 235        int ret;
 236        u8 txbuf[6];
 237
 238        ret = b53_prepare_reg_access(spi, page);
 239        if (ret)
 240                return ret;
 241
 242        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 243        txbuf[1] = reg;
 244        put_unaligned_le32(value, &txbuf[2]);
 245
 246        return spi_write(spi, txbuf, sizeof(txbuf));
 247}
 248
 249static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
 250{
 251        struct spi_device *spi = dev->priv;
 252        int ret;
 253        u8 txbuf[10];
 254
 255        ret = b53_prepare_reg_access(spi, page);
 256        if (ret)
 257                return ret;
 258
 259        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 260        txbuf[1] = reg;
 261        put_unaligned_le64(value, &txbuf[2]);
 262
 263        return spi_write(spi, txbuf, sizeof(txbuf) - 2);
 264}
 265
 266static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
 267{
 268        struct spi_device *spi = dev->priv;
 269        int ret;
 270        u8 txbuf[10];
 271
 272        ret = b53_prepare_reg_access(spi, page);
 273        if (ret)
 274                return ret;
 275
 276        txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 277        txbuf[1] = reg;
 278        put_unaligned_le64(value, &txbuf[2]);
 279
 280        return spi_write(spi, txbuf, sizeof(txbuf));
 281}
 282
 283static const struct b53_io_ops b53_spi_ops = {
 284        .read8 = b53_spi_read8,
 285        .read16 = b53_spi_read16,
 286        .read32 = b53_spi_read32,
 287        .read48 = b53_spi_read48,
 288        .read64 = b53_spi_read64,
 289        .write8 = b53_spi_write8,
 290        .write16 = b53_spi_write16,
 291        .write32 = b53_spi_write32,
 292        .write48 = b53_spi_write48,
 293        .write64 = b53_spi_write64,
 294};
 295
 296static int b53_spi_probe(struct spi_device *spi)
 297{
 298        struct b53_device *dev;
 299        int ret;
 300
 301        dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
 302        if (!dev)
 303                return -ENOMEM;
 304
 305        if (spi->dev.platform_data)
 306                dev->pdata = spi->dev.platform_data;
 307
 308        ret = b53_switch_register(dev);
 309        if (ret)
 310                return ret;
 311
 312        spi_set_drvdata(spi, dev);
 313
 314        return 0;
 315}
 316
 317static int b53_spi_remove(struct spi_device *spi)
 318{
 319        struct b53_device *dev = spi_get_drvdata(spi);
 320
 321        if (dev)
 322                b53_switch_remove(dev);
 323
 324        spi_set_drvdata(spi, NULL);
 325
 326        return 0;
 327}
 328
 329static void b53_spi_shutdown(struct spi_device *spi)
 330{
 331        struct b53_device *dev = spi_get_drvdata(spi);
 332
 333        if (dev)
 334                b53_switch_shutdown(dev);
 335
 336        spi_set_drvdata(spi, NULL);
 337}
 338
 339static const struct of_device_id b53_spi_of_match[] = {
 340        { .compatible = "brcm,bcm5325" },
 341        { .compatible = "brcm,bcm5365" },
 342        { .compatible = "brcm,bcm5395" },
 343        { .compatible = "brcm,bcm5397" },
 344        { .compatible = "brcm,bcm5398" },
 345        { .compatible = "brcm,bcm53115" },
 346        { .compatible = "brcm,bcm53125" },
 347        { .compatible = "brcm,bcm53128" },
 348        { /* sentinel */ }
 349};
 350MODULE_DEVICE_TABLE(of, b53_spi_of_match);
 351
 352static struct spi_driver b53_spi_driver = {
 353        .driver = {
 354                .name   = "b53-switch",
 355                .of_match_table = b53_spi_of_match,
 356        },
 357        .probe  = b53_spi_probe,
 358        .remove = b53_spi_remove,
 359        .shutdown = b53_spi_shutdown,
 360};
 361
 362module_spi_driver(b53_spi_driver);
 363
 364MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
 365MODULE_DESCRIPTION("B53 SPI access driver");
 366MODULE_LICENSE("Dual BSD/GPL");
 367