1/* 2 * SPI driver for the CPLD chip on the Mikrotik RB4xx boards 3 * 4 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> 5 * 6 * This file was based on the patches for Linux 2.6.27.39 published by 7 * MikroTik for their RouterBoard 4xx series devices. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2 as published 11 * by the Free Software Foundation. 12 */ 13 14#include <linux/types.h> 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/init.h> 18#include <linux/module.h> 19#include <linux/device.h> 20#include <linux/bitops.h> 21#include <linux/spi/spi.h> 22#include <linux/gpio.h> 23#include <linux/slab.h> 24 25#include <asm/mach-ath79/rb4xx_cpld.h> 26 27#define DRV_NAME "spi-rb4xx-cpld" 28#define DRV_DESC "RB4xx CPLD driver" 29#define DRV_VERSION "0.1.0" 30 31#define CPLD_CMD_WRITE_NAND 0x08 /* send cmd, n x send data, send indle */ 32#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */ 33#define CPLD_CMD_READ_NAND 0x0a /* send cmd, send idle, n x read data */ 34#define CPLD_CMD_READ_FAST 0x0b /* send cmd, 4 x idle, n x read data */ 35#define CPLD_CMD_LED5_ON 0x0c /* send cmd */ 36#define CPLD_CMD_LED5_OFF 0x0d /* send cmd */ 37 38struct rb4xx_cpld { 39 struct spi_device *spi; 40 struct mutex lock; 41 struct gpio_chip chip; 42 unsigned int config; 43}; 44 45static struct rb4xx_cpld *rb4xx_cpld; 46 47static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip) 48{ 49 return container_of(chip, struct rb4xx_cpld, chip); 50} 51 52static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd) 53{ 54 struct spi_transfer t[1]; 55 struct spi_message m; 56 unsigned char tx_buf[1]; 57 int err; 58 59 spi_message_init(&m); 60 memset(&t, 0, sizeof(t)); 61 62 t[0].tx_buf = tx_buf; 63 t[0].len = sizeof(tx_buf); 64 spi_message_add_tail(&t[0], &m); 65 66 tx_buf[0] = cmd; 67 68 err = spi_sync(cpld->spi, &m); 69 return err; 70} 71 72static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config) 73{ 74 struct spi_transfer t[1]; 75 struct spi_message m; 76 unsigned char cmd[2]; 77 int err; 78 79 spi_message_init(&m); 80 memset(&t, 0, sizeof(t)); 81 82 t[0].tx_buf = cmd; 83 t[0].len = sizeof(cmd); 84 spi_message_add_tail(&t[0], &m); 85 86 cmd[0] = CPLD_CMD_WRITE_CFG; 87 cmd[1] = config; 88 89 err = spi_sync(cpld->spi, &m); 90 return err; 91} 92 93static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask, 94 unsigned value) 95{ 96 unsigned int config; 97 int err; 98 99 config = cpld->config & ~mask; 100 config |= value; 101 102 if ((cpld->config ^ config) & 0xff) { 103 err = rb4xx_cpld_write_cfg(cpld, config); 104 if (err) 105 return err; 106 } 107 108 if ((cpld->config ^ config) & CPLD_CFG_nLED5) { 109 err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON : 110 CPLD_CMD_LED5_OFF); 111 if (err) 112 return err; 113 } 114 115 cpld->config = config; 116 return 0; 117} 118 119int rb4xx_cpld_change_cfg(unsigned mask, unsigned value) 120{ 121 int ret; 122 123 if (rb4xx_cpld == NULL) 124 return -ENODEV; 125 126 mutex_lock(&rb4xx_cpld->lock); 127 ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value); 128 mutex_unlock(&rb4xx_cpld->lock); 129 130 return ret; 131} 132EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg); 133 134int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf, 135 const unsigned char *verify_buf, unsigned count) 136{ 137 const unsigned char cmd[5] = { 138 CPLD_CMD_READ_FAST, 139 (addr >> 16) & 0xff, 140 (addr >> 8) & 0xff, 141 addr & 0xff, 142 0 143 }; 144 struct spi_transfer t[2] = { 145 { 146 .tx_buf = &cmd, 147 .len = 5, 148 }, 149 { 150 .tx_buf = verify_buf, 151 .rx_buf = rx_buf, 152 .len = count, 153 .verify = (verify_buf != NULL), 154 }, 155 }; 156 struct spi_message m; 157 158 if (rb4xx_cpld == NULL) 159 return -ENODEV; 160 161 spi_message_init(&m); 162 m.fast_read = 1; 163 spi_message_add_tail(&t[0], &m); 164 spi_message_add_tail(&t[1], &m); 165 return spi_sync(rb4xx_cpld->spi, &m); 166} 167EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from); 168 169#if 0 170int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf, 171 unsigned count) 172{ 173 struct spi_transfer t[2]; 174 struct spi_message m; 175 unsigned char cmd[2]; 176 177 if (rb4xx_cpld == NULL) 178 return -ENODEV; 179 180 spi_message_init(&m); 181 memset(&t, 0, sizeof(t)); 182 183 /* send command */ 184 t[0].tx_buf = cmd; 185 t[0].len = sizeof(cmd); 186 spi_message_add_tail(&t[0], &m); 187 188 cmd[0] = CPLD_CMD_READ_NAND; 189 cmd[1] = 0; 190 191 /* read data */ 192 t[1].rx_buf = buf; 193 t[1].len = count; 194 spi_message_add_tail(&t[1], &m); 195 196 return spi_sync(rb4xx_cpld->spi, &m); 197} 198#else 199int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf, 200 unsigned count) 201{ 202 static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 }; 203 struct spi_transfer t[2] = { 204 { 205 .tx_buf = &cmd, 206 .len = 2, 207 }, { 208 .tx_buf = verify_buf, 209 .rx_buf = rx_buf, 210 .len = count, 211 .verify = (verify_buf != NULL), 212 }, 213 }; 214 struct spi_message m; 215 216 if (rb4xx_cpld == NULL) 217 return -ENODEV; 218 219 spi_message_init(&m); 220 spi_message_add_tail(&t[0], &m); 221 spi_message_add_tail(&t[1], &m); 222 return spi_sync(rb4xx_cpld->spi, &m); 223} 224#endif 225EXPORT_SYMBOL_GPL(rb4xx_cpld_read); 226 227int rb4xx_cpld_write(const unsigned char *buf, unsigned count) 228{ 229#if 0 230 struct spi_transfer t[3]; 231 struct spi_message m; 232 unsigned char cmd[1]; 233 234 if (rb4xx_cpld == NULL) 235 return -ENODEV; 236 237 memset(&t, 0, sizeof(t)); 238 spi_message_init(&m); 239 240 /* send command */ 241 t[0].tx_buf = cmd; 242 t[0].len = sizeof(cmd); 243 spi_message_add_tail(&t[0], &m); 244 245 cmd[0] = CPLD_CMD_WRITE_NAND; 246 247 /* write data */ 248 t[1].tx_buf = buf; 249 t[1].len = count; 250 spi_message_add_tail(&t[1], &m); 251 252 /* send idle */ 253 t[2].len = 1; 254 spi_message_add_tail(&t[2], &m); 255 256 return spi_sync(rb4xx_cpld->spi, &m); 257#else 258 static const unsigned char cmd = CPLD_CMD_WRITE_NAND; 259 struct spi_transfer t[3] = { 260 { 261 .tx_buf = &cmd, 262 .len = 1, 263 }, { 264 .tx_buf = buf, 265 .len = count, 266 .fast_write = 1, 267 }, { 268 .len = 1, 269 .fast_write = 1, 270 }, 271 }; 272 struct spi_message m; 273 274 if (rb4xx_cpld == NULL) 275 return -ENODEV; 276 277 spi_message_init(&m); 278 spi_message_add_tail(&t[0], &m); 279 spi_message_add_tail(&t[1], &m); 280 spi_message_add_tail(&t[2], &m); 281 return spi_sync(rb4xx_cpld->spi, &m); 282#endif 283} 284EXPORT_SYMBOL_GPL(rb4xx_cpld_write); 285 286static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset) 287{ 288 struct rb4xx_cpld *cpld = gpio_to_cpld(chip); 289 int ret; 290 291 mutex_lock(&cpld->lock); 292 ret = (cpld->config >> offset) & 1; 293 mutex_unlock(&cpld->lock); 294 295 return ret; 296} 297 298static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset, 299 int value) 300{ 301 struct rb4xx_cpld *cpld = gpio_to_cpld(chip); 302 303 mutex_lock(&cpld->lock); 304 __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset); 305 mutex_unlock(&cpld->lock); 306} 307 308static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip, 309 unsigned offset) 310{ 311 return -EOPNOTSUPP; 312} 313 314static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip, 315 unsigned offset, 316 int value) 317{ 318 struct rb4xx_cpld *cpld = gpio_to_cpld(chip); 319 int ret; 320 321 mutex_lock(&cpld->lock); 322 ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset); 323 mutex_unlock(&cpld->lock); 324 325 return ret; 326} 327 328static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base) 329{ 330 int err; 331 332 /* init config */ 333 cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 | 334 CPLD_CFG_nLED4 | CPLD_CFG_nCE; 335 rb4xx_cpld_write_cfg(cpld, cpld->config); 336 337 /* setup GPIO chip */ 338 cpld->chip.label = DRV_NAME; 339 340 cpld->chip.get = rb4xx_cpld_gpio_get; 341 cpld->chip.set = rb4xx_cpld_gpio_set; 342 cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input; 343 cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output; 344 345 cpld->chip.base = base; 346 cpld->chip.ngpio = CPLD_NUM_GPIOS; 347 cpld->chip.can_sleep = 1; 348 cpld->chip.dev = &cpld->spi->dev; 349 cpld->chip.owner = THIS_MODULE; 350 351 err = gpiochip_add(&cpld->chip); 352 if (err) 353 dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n", 354 err); 355 356 return err; 357} 358 359static int rb4xx_cpld_probe(struct spi_device *spi) 360{ 361 struct rb4xx_cpld *cpld; 362 struct rb4xx_cpld_platform_data *pdata; 363 int err; 364 365 pdata = spi->dev.platform_data; 366 if (!pdata) { 367 dev_dbg(&spi->dev, "no platform data\n"); 368 return -EINVAL; 369 } 370 371 cpld = kzalloc(sizeof(*cpld), GFP_KERNEL); 372 if (!cpld) { 373 dev_err(&spi->dev, "no memory for private data\n"); 374 return -ENOMEM; 375 } 376 377 mutex_init(&cpld->lock); 378 cpld->spi = spi_dev_get(spi); 379 dev_set_drvdata(&spi->dev, cpld); 380 381 spi->mode = SPI_MODE_0; 382 spi->bits_per_word = 8; 383 err = spi_setup(spi); 384 if (err) { 385 dev_err(&spi->dev, "spi_setup failed, err=%d\n", err); 386 goto err_drvdata; 387 } 388 389 err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base); 390 if (err) 391 goto err_drvdata; 392 393 rb4xx_cpld = cpld; 394 395 return 0; 396 397err_drvdata: 398 dev_set_drvdata(&spi->dev, NULL); 399 kfree(cpld); 400 401 return err; 402} 403 404static int rb4xx_cpld_remove(struct spi_device *spi) 405{ 406 struct rb4xx_cpld *cpld; 407 408 rb4xx_cpld = NULL; 409 cpld = dev_get_drvdata(&spi->dev); 410 dev_set_drvdata(&spi->dev, NULL); 411 kfree(cpld); 412 413 return 0; 414} 415 416static struct spi_driver rb4xx_cpld_driver = { 417 .driver = { 418 .name = DRV_NAME, 419 .bus = &spi_bus_type, 420 .owner = THIS_MODULE, 421 }, 422 .probe = rb4xx_cpld_probe, 423 .remove = rb4xx_cpld_remove, 424}; 425 426static int __init rb4xx_cpld_init(void) 427{ 428 return spi_register_driver(&rb4xx_cpld_driver); 429} 430module_init(rb4xx_cpld_init); 431 432static void __exit rb4xx_cpld_exit(void) 433{ 434 spi_unregister_driver(&rb4xx_cpld_driver); 435} 436module_exit(rb4xx_cpld_exit); 437 438MODULE_DESCRIPTION(DRV_DESC); 439MODULE_VERSION(DRV_VERSION); 440MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); 441MODULE_LICENSE("GPL v2"); 442