Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * B53 register access through SPI
0003  *
0004  * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
0005  *
0006  * Permission to use, copy, modify, and/or distribute this software for any
0007  * purpose with or without fee is hereby granted, provided that the above
0008  * copyright notice and this permission notice appear in all copies.
0009  *
0010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0017  */
0018 
0019 #include <asm/unaligned.h>
0020 
0021 #include <linux/delay.h>
0022 #include <linux/kernel.h>
0023 #include <linux/module.h>
0024 #include <linux/spi/spi.h>
0025 #include <linux/platform_data/b53.h>
0026 
0027 #include "b53_priv.h"
0028 
0029 #define B53_SPI_DATA        0xf0
0030 
0031 #define B53_SPI_STATUS      0xfe
0032 #define B53_SPI_CMD_SPIF    BIT(7)
0033 #define B53_SPI_CMD_RACK    BIT(5)
0034 
0035 #define B53_SPI_CMD_READ    0x00
0036 #define B53_SPI_CMD_WRITE   0x01
0037 #define B53_SPI_CMD_NORMAL  0x60
0038 #define B53_SPI_CMD_FAST    0x10
0039 
0040 #define B53_SPI_PAGE_SELECT 0xff
0041 
0042 static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
0043                    unsigned int len)
0044 {
0045     u8 txbuf[2];
0046 
0047     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
0048     txbuf[1] = reg;
0049 
0050     return spi_write_then_read(spi, txbuf, 2, val, len);
0051 }
0052 
0053 static inline int b53_spi_clear_status(struct spi_device *spi)
0054 {
0055     unsigned int i;
0056     u8 rxbuf;
0057     int ret;
0058 
0059     for (i = 0; i < 10; i++) {
0060         ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
0061         if (ret)
0062             return ret;
0063 
0064         if (!(rxbuf & B53_SPI_CMD_SPIF))
0065             break;
0066 
0067         mdelay(1);
0068     }
0069 
0070     if (i == 10)
0071         return -EIO;
0072 
0073     return 0;
0074 }
0075 
0076 static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
0077 {
0078     u8 txbuf[3];
0079 
0080     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
0081     txbuf[1] = B53_SPI_PAGE_SELECT;
0082     txbuf[2] = page;
0083 
0084     return spi_write(spi, txbuf, sizeof(txbuf));
0085 }
0086 
0087 static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
0088 {
0089     int ret = b53_spi_clear_status(spi);
0090 
0091     if (ret)
0092         return ret;
0093 
0094     return b53_spi_set_page(spi, page);
0095 }
0096 
0097 static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
0098 {
0099     u8 rxbuf;
0100     int retry_count;
0101     int ret;
0102 
0103     ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
0104     if (ret)
0105         return ret;
0106 
0107     for (retry_count = 0; retry_count < 10; retry_count++) {
0108         ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
0109         if (ret)
0110             return ret;
0111 
0112         if (rxbuf & B53_SPI_CMD_RACK)
0113             break;
0114 
0115         mdelay(1);
0116     }
0117 
0118     if (retry_count == 10)
0119         return -EIO;
0120 
0121     return 0;
0122 }
0123 
0124 static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
0125             unsigned int len)
0126 {
0127     struct spi_device *spi = dev->priv;
0128     int ret;
0129 
0130     ret = b53_prepare_reg_access(spi, page);
0131     if (ret)
0132         return ret;
0133 
0134     ret = b53_spi_prepare_reg_read(spi, reg);
0135     if (ret)
0136         return ret;
0137 
0138     return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
0139 }
0140 
0141 static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
0142 {
0143     return b53_spi_read(dev, page, reg, val, 1);
0144 }
0145 
0146 static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
0147 {
0148     __le16 value;
0149     int ret;
0150 
0151     ret = b53_spi_read(dev, page, reg, (u8 *)&value, 2);
0152 
0153     if (!ret)
0154         *val = le16_to_cpu(value);
0155 
0156     return ret;
0157 }
0158 
0159 static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
0160 {
0161     __le32 value;
0162     int ret;
0163 
0164     ret = b53_spi_read(dev, page, reg, (u8 *)&value, 4);
0165 
0166     if (!ret)
0167         *val = le32_to_cpu(value);
0168 
0169     return ret;
0170 }
0171 
0172 static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
0173 {
0174     __le64 value;
0175     int ret;
0176 
0177     *val = 0;
0178     ret = b53_spi_read(dev, page, reg, (u8 *)&value, 6);
0179     if (!ret)
0180         *val = le64_to_cpu(value);
0181 
0182     return ret;
0183 }
0184 
0185 static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
0186 {
0187     __le64 value;
0188     int ret;
0189 
0190     ret = b53_spi_read(dev, page, reg, (u8 *)&value, 8);
0191 
0192     if (!ret)
0193         *val = le64_to_cpu(value);
0194 
0195     return ret;
0196 }
0197 
0198 static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
0199 {
0200     struct spi_device *spi = dev->priv;
0201     int ret;
0202     u8 txbuf[3];
0203 
0204     ret = b53_prepare_reg_access(spi, page);
0205     if (ret)
0206         return ret;
0207 
0208     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
0209     txbuf[1] = reg;
0210     txbuf[2] = value;
0211 
0212     return spi_write(spi, txbuf, sizeof(txbuf));
0213 }
0214 
0215 static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
0216 {
0217     struct spi_device *spi = dev->priv;
0218     int ret;
0219     u8 txbuf[4];
0220 
0221     ret = b53_prepare_reg_access(spi, page);
0222     if (ret)
0223         return ret;
0224 
0225     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
0226     txbuf[1] = reg;
0227     put_unaligned_le16(value, &txbuf[2]);
0228 
0229     return spi_write(spi, txbuf, sizeof(txbuf));
0230 }
0231 
0232 static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
0233 {
0234     struct spi_device *spi = dev->priv;
0235     int ret;
0236     u8 txbuf[6];
0237 
0238     ret = b53_prepare_reg_access(spi, page);
0239     if (ret)
0240         return ret;
0241 
0242     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
0243     txbuf[1] = reg;
0244     put_unaligned_le32(value, &txbuf[2]);
0245 
0246     return spi_write(spi, txbuf, sizeof(txbuf));
0247 }
0248 
0249 static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
0250 {
0251     struct spi_device *spi = dev->priv;
0252     int ret;
0253     u8 txbuf[10];
0254 
0255     ret = b53_prepare_reg_access(spi, page);
0256     if (ret)
0257         return ret;
0258 
0259     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
0260     txbuf[1] = reg;
0261     put_unaligned_le64(value, &txbuf[2]);
0262 
0263     return spi_write(spi, txbuf, sizeof(txbuf) - 2);
0264 }
0265 
0266 static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
0267 {
0268     struct spi_device *spi = dev->priv;
0269     int ret;
0270     u8 txbuf[10];
0271 
0272     ret = b53_prepare_reg_access(spi, page);
0273     if (ret)
0274         return ret;
0275 
0276     txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
0277     txbuf[1] = reg;
0278     put_unaligned_le64(value, &txbuf[2]);
0279 
0280     return spi_write(spi, txbuf, sizeof(txbuf));
0281 }
0282 
0283 static const struct b53_io_ops b53_spi_ops = {
0284     .read8 = b53_spi_read8,
0285     .read16 = b53_spi_read16,
0286     .read32 = b53_spi_read32,
0287     .read48 = b53_spi_read48,
0288     .read64 = b53_spi_read64,
0289     .write8 = b53_spi_write8,
0290     .write16 = b53_spi_write16,
0291     .write32 = b53_spi_write32,
0292     .write48 = b53_spi_write48,
0293     .write64 = b53_spi_write64,
0294 };
0295 
0296 static int b53_spi_probe(struct spi_device *spi)
0297 {
0298     struct b53_device *dev;
0299     int ret;
0300 
0301     dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
0302     if (!dev)
0303         return -ENOMEM;
0304 
0305     if (spi->dev.platform_data)
0306         dev->pdata = spi->dev.platform_data;
0307 
0308     ret = b53_switch_register(dev);
0309     if (ret)
0310         return ret;
0311 
0312     spi_set_drvdata(spi, dev);
0313 
0314     return 0;
0315 }
0316 
0317 static void b53_spi_remove(struct spi_device *spi)
0318 {
0319     struct b53_device *dev = spi_get_drvdata(spi);
0320 
0321     if (dev)
0322         b53_switch_remove(dev);
0323 }
0324 
0325 static void b53_spi_shutdown(struct spi_device *spi)
0326 {
0327     struct b53_device *dev = spi_get_drvdata(spi);
0328 
0329     if (dev)
0330         b53_switch_shutdown(dev);
0331 
0332     spi_set_drvdata(spi, NULL);
0333 }
0334 
0335 static const struct of_device_id b53_spi_of_match[] = {
0336     { .compatible = "brcm,bcm5325" },
0337     { .compatible = "brcm,bcm5365" },
0338     { .compatible = "brcm,bcm5395" },
0339     { .compatible = "brcm,bcm5397" },
0340     { .compatible = "brcm,bcm5398" },
0341     { .compatible = "brcm,bcm53115" },
0342     { .compatible = "brcm,bcm53125" },
0343     { .compatible = "brcm,bcm53128" },
0344     { /* sentinel */ }
0345 };
0346 MODULE_DEVICE_TABLE(of, b53_spi_of_match);
0347 
0348 static const struct spi_device_id b53_spi_ids[] = {
0349     { .name = "bcm5325" },
0350     { .name = "bcm5365" },
0351     { .name = "bcm5395" },
0352     { .name = "bcm5397" },
0353     { .name = "bcm5398" },
0354     { .name = "bcm53115" },
0355     { .name = "bcm53125" },
0356     { .name = "bcm53128" },
0357     { /* sentinel */ }
0358 };
0359 MODULE_DEVICE_TABLE(spi, b53_spi_ids);
0360 
0361 static struct spi_driver b53_spi_driver = {
0362     .driver = {
0363         .name   = "b53-switch",
0364         .of_match_table = b53_spi_of_match,
0365     },
0366     .probe  = b53_spi_probe,
0367     .remove = b53_spi_remove,
0368     .shutdown = b53_spi_shutdown,
0369     .id_table = b53_spi_ids,
0370 };
0371 
0372 module_spi_driver(b53_spi_driver);
0373 
0374 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
0375 MODULE_DESCRIPTION("B53 SPI access driver");
0376 MODULE_LICENSE("Dual BSD/GPL");