Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Florian Fainelli | 1448 | 99.93% | 1 | 50.00% |
Julia Lawall | 1 | 0.07% | 1 | 50.00% |
Total | 1449 | 2 |
/* * B53 register access through SPI * * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <asm/unaligned.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/platform_data/b53.h> #include "b53_priv.h" #define B53_SPI_DATA 0xf0 #define B53_SPI_STATUS 0xfe #define B53_SPI_CMD_SPIF BIT(7) #define B53_SPI_CMD_RACK BIT(5) #define B53_SPI_CMD_READ 0x00 #define B53_SPI_CMD_WRITE 0x01 #define B53_SPI_CMD_NORMAL 0x60 #define B53_SPI_CMD_FAST 0x10 #define B53_SPI_PAGE_SELECT 0xff static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, unsigned int len) { u8 txbuf[2]; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; txbuf[1] = reg; return spi_write_then_read(spi, txbuf, 2, val, len); } static inline int b53_spi_clear_status(struct spi_device *spi) { unsigned int i; u8 rxbuf; int ret; for (i = 0; i < 10; i++) { ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); if (ret) return ret; if (!(rxbuf & B53_SPI_CMD_SPIF)) break; mdelay(1); } if (i == 10) return -EIO; return 0; } static inline int b53_spi_set_page(struct spi_device *spi, u8 page) { u8 txbuf[3]; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; txbuf[1] = B53_SPI_PAGE_SELECT; txbuf[2] = page; return spi_write(spi, txbuf, sizeof(txbuf)); } static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) { int ret = b53_spi_clear_status(spi); if (ret) return ret; return b53_spi_set_page(spi, page); } static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) { u8 rxbuf; int retry_count; int ret; ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); if (ret) return ret; for (retry_count = 0; retry_count < 10; retry_count++) { ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); if (ret) return ret; if (rxbuf & B53_SPI_CMD_RACK) break; mdelay(1); } if (retry_count == 10) return -EIO; return 0; } static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, unsigned int len) { struct spi_device *spi = dev->priv; int ret; ret = b53_prepare_reg_access(spi, page); if (ret) return ret; ret = b53_spi_prepare_reg_read(spi, reg); if (ret) return ret; return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); } static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) { return b53_spi_read(dev, page, reg, val, 1); } static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) { int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); if (!ret) *val = le16_to_cpu(*val); return ret; } static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) { int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); if (!ret) *val = le32_to_cpu(*val); return ret; } static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) { int ret; *val = 0; ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); if (!ret) *val = le64_to_cpu(*val); return ret; } static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) { int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); if (!ret) *val = le64_to_cpu(*val); return ret; } static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) { struct spi_device *spi = dev->priv; int ret; u8 txbuf[3]; ret = b53_prepare_reg_access(spi, page); if (ret) return ret; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; txbuf[1] = reg; txbuf[2] = value; return spi_write(spi, txbuf, sizeof(txbuf)); } static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) { struct spi_device *spi = dev->priv; int ret; u8 txbuf[4]; ret = b53_prepare_reg_access(spi, page); if (ret) return ret; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; txbuf[1] = reg; put_unaligned_le16(value, &txbuf[2]); return spi_write(spi, txbuf, sizeof(txbuf)); } static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) { struct spi_device *spi = dev->priv; int ret; u8 txbuf[6]; ret = b53_prepare_reg_access(spi, page); if (ret) return ret; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; txbuf[1] = reg; put_unaligned_le32(value, &txbuf[2]); return spi_write(spi, txbuf, sizeof(txbuf)); } static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) { struct spi_device *spi = dev->priv; int ret; u8 txbuf[10]; ret = b53_prepare_reg_access(spi, page); if (ret) return ret; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; txbuf[1] = reg; put_unaligned_le64(value, &txbuf[2]); return spi_write(spi, txbuf, sizeof(txbuf) - 2); } static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) { struct spi_device *spi = dev->priv; int ret; u8 txbuf[10]; ret = b53_prepare_reg_access(spi, page); if (ret) return ret; txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; txbuf[1] = reg; put_unaligned_le64(value, &txbuf[2]); return spi_write(spi, txbuf, sizeof(txbuf)); } static const struct b53_io_ops b53_spi_ops = { .read8 = b53_spi_read8, .read16 = b53_spi_read16, .read32 = b53_spi_read32, .read48 = b53_spi_read48, .read64 = b53_spi_read64, .write8 = b53_spi_write8, .write16 = b53_spi_write16, .write32 = b53_spi_write32, .write48 = b53_spi_write48, .write64 = b53_spi_write64, }; static int b53_spi_probe(struct spi_device *spi) { struct b53_device *dev; int ret; dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi); if (!dev) return -ENOMEM; if (spi->dev.platform_data) dev->pdata = spi->dev.platform_data; ret = b53_switch_register(dev); if (ret) return ret; spi_set_drvdata(spi, dev); return 0; } static int b53_spi_remove(struct spi_device *spi) { struct b53_device *dev = spi_get_drvdata(spi); if (dev) b53_switch_remove(dev); return 0; } static struct spi_driver b53_spi_driver = { .driver = { .name = "b53-switch", }, .probe = b53_spi_probe, .remove = b53_spi_remove, }; module_spi_driver(b53_spi_driver); MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); MODULE_DESCRIPTION("B53 SPI access driver"); MODULE_LICENSE("Dual BSD/GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1