Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.9 276 lines 7.0 kB view raw
1/* 2 * Copyright 2011, Netlogic Microsystems Inc. 3 * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> 4 * 5 * This file is licensed under the terms of the GNU General Public 6 * License version 2. This program is licensed "as is" without any 7 * warranty of any kind, whether express or implied. 8 */ 9 10#include <linux/err.h> 11#include <linux/kernel.h> 12#include <linux/module.h> 13#include <linux/slab.h> 14#include <linux/init.h> 15#include <linux/ioport.h> 16#include <linux/delay.h> 17#include <linux/errno.h> 18#include <linux/i2c.h> 19#include <linux/io.h> 20#include <linux/platform_device.h> 21 22/* XLR I2C REGISTERS */ 23#define XLR_I2C_CFG 0x00 24#define XLR_I2C_CLKDIV 0x01 25#define XLR_I2C_DEVADDR 0x02 26#define XLR_I2C_ADDR 0x03 27#define XLR_I2C_DATAOUT 0x04 28#define XLR_I2C_DATAIN 0x05 29#define XLR_I2C_STATUS 0x06 30#define XLR_I2C_STARTXFR 0x07 31#define XLR_I2C_BYTECNT 0x08 32#define XLR_I2C_HDSTATIM 0x09 33 34/* XLR I2C REGISTERS FLAGS */ 35#define XLR_I2C_BUS_BUSY 0x01 36#define XLR_I2C_SDOEMPTY 0x02 37#define XLR_I2C_RXRDY 0x04 38#define XLR_I2C_ACK_ERR 0x08 39#define XLR_I2C_ARB_STARTERR 0x30 40 41/* Register Values */ 42#define XLR_I2C_CFG_ADDR 0xF8 43#define XLR_I2C_CFG_NOADDR 0xFA 44#define XLR_I2C_STARTXFR_ND 0x02 /* No Data */ 45#define XLR_I2C_STARTXFR_RD 0x01 /* Read */ 46#define XLR_I2C_STARTXFR_WR 0x00 /* Write */ 47 48#define XLR_I2C_TIMEOUT 10 /* timeout per byte in msec */ 49 50/* 51 * On XLR/XLS, we need to use __raw_ IO to read the I2C registers 52 * because they are in the big-endian MMIO area on the SoC. 53 * 54 * The readl/writel implementation on XLR/XLS byteswaps, because 55 * those are for its little-endian PCI space (see arch/mips/Kconfig). 56 */ 57static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val) 58{ 59 __raw_writel(val, base + reg); 60} 61 62static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg) 63{ 64 return __raw_readl(base + reg); 65} 66 67struct xlr_i2c_private { 68 struct i2c_adapter adap; 69 u32 __iomem *iobase; 70}; 71 72static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len, 73 u8 *buf, u16 addr) 74{ 75 struct i2c_adapter *adap = &priv->adap; 76 unsigned long timeout, stoptime, checktime; 77 u32 i2c_status; 78 int pos, timedout; 79 u8 offset, byte; 80 81 offset = buf[0]; 82 xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset); 83 xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); 84 xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR); 85 xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); 86 87 timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); 88 stoptime = jiffies + timeout; 89 timedout = 0; 90 pos = 1; 91retry: 92 if (len == 1) { 93 xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, 94 XLR_I2C_STARTXFR_ND); 95 } else { 96 xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]); 97 xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, 98 XLR_I2C_STARTXFR_WR); 99 } 100 101 while (!timedout) { 102 checktime = jiffies; 103 i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); 104 105 if (i2c_status & XLR_I2C_SDOEMPTY) { 106 pos++; 107 /* need to do a empty dataout after the last byte */ 108 byte = (pos < len) ? buf[pos] : 0; 109 xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte); 110 111 /* reset timeout on successful xmit */ 112 stoptime = jiffies + timeout; 113 } 114 timedout = time_after(checktime, stoptime); 115 116 if (i2c_status & XLR_I2C_ARB_STARTERR) { 117 if (timedout) 118 break; 119 goto retry; 120 } 121 122 if (i2c_status & XLR_I2C_ACK_ERR) 123 return -EIO; 124 125 if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len) 126 return 0; 127 } 128 dev_err(&adap->dev, "I2C transmit timeout\n"); 129 return -ETIMEDOUT; 130} 131 132static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr) 133{ 134 struct i2c_adapter *adap = &priv->adap; 135 u32 i2c_status; 136 unsigned long timeout, stoptime, checktime; 137 int nbytes, timedout; 138 u8 byte; 139 140 xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR); 141 xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len); 142 xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); 143 144 timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); 145 stoptime = jiffies + timeout; 146 timedout = 0; 147 nbytes = 0; 148retry: 149 xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD); 150 151 while (!timedout) { 152 checktime = jiffies; 153 i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); 154 if (i2c_status & XLR_I2C_RXRDY) { 155 if (nbytes > len) 156 return -EIO; /* should not happen */ 157 158 /* we need to do a dummy datain when nbytes == len */ 159 byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN); 160 if (nbytes < len) 161 buf[nbytes] = byte; 162 nbytes++; 163 164 /* reset timeout on successful read */ 165 stoptime = jiffies + timeout; 166 } 167 168 timedout = time_after(checktime, stoptime); 169 if (i2c_status & XLR_I2C_ARB_STARTERR) { 170 if (timedout) 171 break; 172 goto retry; 173 } 174 175 if (i2c_status & XLR_I2C_ACK_ERR) 176 return -EIO; 177 178 if ((i2c_status & XLR_I2C_BUS_BUSY) == 0) 179 return 0; 180 } 181 182 dev_err(&adap->dev, "I2C receive timeout\n"); 183 return -ETIMEDOUT; 184} 185 186static int xlr_i2c_xfer(struct i2c_adapter *adap, 187 struct i2c_msg *msgs, int num) 188{ 189 struct i2c_msg *msg; 190 int i; 191 int ret = 0; 192 struct xlr_i2c_private *priv = i2c_get_adapdata(adap); 193 194 for (i = 0; ret == 0 && i < num; i++) { 195 msg = &msgs[i]; 196 if (msg->flags & I2C_M_RD) 197 ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0], 198 msg->addr); 199 else 200 ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0], 201 msg->addr); 202 } 203 204 return (ret != 0) ? ret : num; 205} 206 207static u32 xlr_func(struct i2c_adapter *adap) 208{ 209 /* Emulate SMBUS over I2C */ 210 return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; 211} 212 213static struct i2c_algorithm xlr_i2c_algo = { 214 .master_xfer = xlr_i2c_xfer, 215 .functionality = xlr_func, 216}; 217 218static int xlr_i2c_probe(struct platform_device *pdev) 219{ 220 struct xlr_i2c_private *priv; 221 struct resource *res; 222 int ret; 223 224 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 225 if (!priv) 226 return -ENOMEM; 227 228 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 229 priv->iobase = devm_ioremap_resource(&pdev->dev, res); 230 if (IS_ERR(priv->iobase)) 231 return PTR_ERR(priv->iobase); 232 233 priv->adap.dev.parent = &pdev->dev; 234 priv->adap.owner = THIS_MODULE; 235 priv->adap.algo_data = priv; 236 priv->adap.algo = &xlr_i2c_algo; 237 priv->adap.nr = pdev->id; 238 priv->adap.class = I2C_CLASS_HWMON; 239 snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); 240 241 i2c_set_adapdata(&priv->adap, priv); 242 ret = i2c_add_numbered_adapter(&priv->adap); 243 if (ret < 0) { 244 dev_err(&priv->adap.dev, "Failed to add i2c bus.\n"); 245 return ret; 246 } 247 248 platform_set_drvdata(pdev, priv); 249 dev_info(&priv->adap.dev, "Added I2C Bus.\n"); 250 return 0; 251} 252 253static int xlr_i2c_remove(struct platform_device *pdev) 254{ 255 struct xlr_i2c_private *priv; 256 257 priv = platform_get_drvdata(pdev); 258 i2c_del_adapter(&priv->adap); 259 return 0; 260} 261 262static struct platform_driver xlr_i2c_driver = { 263 .probe = xlr_i2c_probe, 264 .remove = xlr_i2c_remove, 265 .driver = { 266 .name = "xlr-i2cbus", 267 .owner = THIS_MODULE, 268 }, 269}; 270 271module_platform_driver(xlr_i2c_driver); 272 273MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>"); 274MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver"); 275MODULE_LICENSE("GPL v2"); 276MODULE_ALIAS("platform:xlr-i2cbus");