b53_spi.c (8032B)
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 void 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 327static void b53_spi_shutdown(struct spi_device *spi) 328{ 329 struct b53_device *dev = spi_get_drvdata(spi); 330 331 if (dev) 332 b53_switch_shutdown(dev); 333 334 spi_set_drvdata(spi, NULL); 335} 336 337static const struct of_device_id b53_spi_of_match[] = { 338 { .compatible = "brcm,bcm5325" }, 339 { .compatible = "brcm,bcm5365" }, 340 { .compatible = "brcm,bcm5395" }, 341 { .compatible = "brcm,bcm5397" }, 342 { .compatible = "brcm,bcm5398" }, 343 { .compatible = "brcm,bcm53115" }, 344 { .compatible = "brcm,bcm53125" }, 345 { .compatible = "brcm,bcm53128" }, 346 { /* sentinel */ } 347}; 348MODULE_DEVICE_TABLE(of, b53_spi_of_match); 349 350static const struct spi_device_id b53_spi_ids[] = { 351 { .name = "bcm5325" }, 352 { .name = "bcm5365" }, 353 { .name = "bcm5395" }, 354 { .name = "bcm5397" }, 355 { .name = "bcm5398" }, 356 { .name = "bcm53115" }, 357 { .name = "bcm53125" }, 358 { .name = "bcm53128" }, 359 { /* sentinel */ } 360}; 361MODULE_DEVICE_TABLE(spi, b53_spi_ids); 362 363static struct spi_driver b53_spi_driver = { 364 .driver = { 365 .name = "b53-switch", 366 .of_match_table = b53_spi_of_match, 367 }, 368 .probe = b53_spi_probe, 369 .remove = b53_spi_remove, 370 .shutdown = b53_spi_shutdown, 371 .id_table = b53_spi_ids, 372}; 373 374module_spi_driver(b53_spi_driver); 375 376MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 377MODULE_DESCRIPTION("B53 SPI access driver"); 378MODULE_LICENSE("Dual BSD/GPL");