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 42 static 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 53 static 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 76 static 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 87 static 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 97 static 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 124 static 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 141 static 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 146 static 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 159 static 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 172 static 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 185 static 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 198 static 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 215 static 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 232 static 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 249 static 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 266 static 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 283 static 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 296 static 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 317 static 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 return 0; 325 } 326 327 static const struct of_device_id b53_spi_of_match[] = { 328 { .compatible = "brcm,bcm5325" }, 329 { .compatible = "brcm,bcm5365" }, 330 { .compatible = "brcm,bcm5395" }, 331 { .compatible = "brcm,bcm5397" }, 332 { .compatible = "brcm,bcm5398" }, 333 { .compatible = "brcm,bcm53115" }, 334 { .compatible = "brcm,bcm53125" }, 335 { .compatible = "brcm,bcm53128" }, 336 { /* sentinel */ } 337 }; 338 MODULE_DEVICE_TABLE(of, b53_spi_of_match); 339 340 static struct spi_driver b53_spi_driver = { 341 .driver = { 342 .name = "b53-switch", 343 .of_match_table = b53_spi_of_match, 344 }, 345 .probe = b53_spi_probe, 346 .remove = b53_spi_remove, 347 }; 348 349 module_spi_driver(b53_spi_driver); 350 351 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 352 MODULE_DESCRIPTION("B53 SPI access driver"); 353 MODULE_LICENSE("Dual BSD/GPL"); 354