dm355evm_msp.c (11349B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * dm355evm_msp.c - driver for MSP430 firmware on DM355EVM board 4 * 5 * Copyright (C) 2008 David Brownell 6 */ 7 8#include <linux/init.h> 9#include <linux/mutex.h> 10#include <linux/platform_device.h> 11#include <linux/clk.h> 12#include <linux/module.h> 13#include <linux/err.h> 14#include <linux/gpio.h> 15#include <linux/gpio/machine.h> 16#include <linux/leds.h> 17#include <linux/i2c.h> 18#include <linux/mfd/dm355evm_msp.h> 19 20 21/* 22 * The DM355 is a DaVinci chip with video support but no C64+ DSP. Its 23 * EVM board has an MSP430 programmed with firmware for various board 24 * support functions. This driver exposes some of them directly, and 25 * supports other drivers (e.g. RTC, input) for more complex access. 26 * 27 * Because this firmware is entirely board-specific, this file embeds 28 * knowledge that would be passed as platform_data in a generic driver. 29 * 30 * This driver was tested with firmware revision A4. 31 */ 32 33#if IS_ENABLED(CONFIG_INPUT_DM355EVM) 34#define msp_has_keyboard() true 35#else 36#define msp_has_keyboard() false 37#endif 38 39#if IS_ENABLED(CONFIG_LEDS_GPIO) 40#define msp_has_leds() true 41#else 42#define msp_has_leds() false 43#endif 44 45#if IS_ENABLED(CONFIG_RTC_DRV_DM355EVM) 46#define msp_has_rtc() true 47#else 48#define msp_has_rtc() false 49#endif 50 51#if IS_ENABLED(CONFIG_VIDEO_TVP514X) 52#define msp_has_tvp() true 53#else 54#define msp_has_tvp() false 55#endif 56 57 58/*----------------------------------------------------------------------*/ 59 60/* REVISIT for paranoia's sake, retry reads/writes on error */ 61 62static struct i2c_client *msp430; 63 64/** 65 * dm355evm_msp_write - Writes a register in dm355evm_msp 66 * @value: the value to be written 67 * @reg: register address 68 * 69 * Returns result of operation - 0 is success, else negative errno 70 */ 71int dm355evm_msp_write(u8 value, u8 reg) 72{ 73 return i2c_smbus_write_byte_data(msp430, reg, value); 74} 75EXPORT_SYMBOL(dm355evm_msp_write); 76 77/** 78 * dm355evm_msp_read - Reads a register from dm355evm_msp 79 * @reg: register address 80 * 81 * Returns result of operation - value, or negative errno 82 */ 83int dm355evm_msp_read(u8 reg) 84{ 85 return i2c_smbus_read_byte_data(msp430, reg); 86} 87EXPORT_SYMBOL(dm355evm_msp_read); 88 89/*----------------------------------------------------------------------*/ 90 91/* 92 * Many of the msp430 pins are just used as fixed-direction GPIOs. 93 * We could export a few more of them this way, if we wanted. 94 */ 95#define MSP_GPIO(bit, reg) ((DM355EVM_MSP_ ## reg) << 3 | (bit)) 96 97static const u8 msp_gpios[] = { 98 /* eight leds */ 99 MSP_GPIO(0, LED), MSP_GPIO(1, LED), 100 MSP_GPIO(2, LED), MSP_GPIO(3, LED), 101 MSP_GPIO(4, LED), MSP_GPIO(5, LED), 102 MSP_GPIO(6, LED), MSP_GPIO(7, LED), 103 /* SW6 and the NTSC/nPAL jumper */ 104 MSP_GPIO(0, SWITCH1), MSP_GPIO(1, SWITCH1), 105 MSP_GPIO(2, SWITCH1), MSP_GPIO(3, SWITCH1), 106 MSP_GPIO(4, SWITCH1), 107 /* switches on MMC/SD sockets */ 108 /* 109 * Note: EVMDM355_ECP_VA4.pdf suggests that Bit 2 and 4 should be 110 * checked for card detection. However on the EVM bit 1 and 3 gives 111 * this status, for 0 and 1 instance respectively. The pdf also 112 * suggests that Bit 1 and 3 should be checked for write protection. 113 * However on the EVM bit 2 and 4 gives this status,for 0 and 1 114 * instance respectively. 115 */ 116 MSP_GPIO(2, SDMMC), MSP_GPIO(1, SDMMC), /* mmc0 WP, nCD */ 117 MSP_GPIO(4, SDMMC), MSP_GPIO(3, SDMMC), /* mmc1 WP, nCD */ 118}; 119 120static struct gpio_led evm_leds[] = { 121 { .name = "dm355evm::ds14", 122 .default_trigger = "heartbeat", }, 123 { .name = "dm355evm::ds15", 124 .default_trigger = "mmc0", }, 125 { .name = "dm355evm::ds16", 126 /* could also be a CE-ATA drive */ 127 .default_trigger = "mmc1", }, 128 { .name = "dm355evm::ds17", 129 .default_trigger = "nand-disk", }, 130 { .name = "dm355evm::ds18", }, 131 { .name = "dm355evm::ds19", }, 132 { .name = "dm355evm::ds20", }, 133 { .name = "dm355evm::ds21", }, 134}; 135 136static struct gpio_led_platform_data evm_led_data = { 137 .num_leds = ARRAY_SIZE(evm_leds), 138 .leds = evm_leds, 139}; 140 141static struct gpiod_lookup_table evm_leds_gpio_table = { 142 .dev_id = "leds-gpio", 143 .table = { 144 /* 145 * These GPIOs are on the dm355evm_msp 146 * GPIO chip at index 0..7 147 */ 148 GPIO_LOOKUP_IDX("dm355evm_msp", 0, NULL, 149 0, GPIO_ACTIVE_LOW), 150 GPIO_LOOKUP_IDX("dm355evm_msp", 1, NULL, 151 1, GPIO_ACTIVE_LOW), 152 GPIO_LOOKUP_IDX("dm355evm_msp", 2, NULL, 153 2, GPIO_ACTIVE_LOW), 154 GPIO_LOOKUP_IDX("dm355evm_msp", 3, NULL, 155 3, GPIO_ACTIVE_LOW), 156 GPIO_LOOKUP_IDX("dm355evm_msp", 4, NULL, 157 4, GPIO_ACTIVE_LOW), 158 GPIO_LOOKUP_IDX("dm355evm_msp", 5, NULL, 159 5, GPIO_ACTIVE_LOW), 160 GPIO_LOOKUP_IDX("dm355evm_msp", 6, NULL, 161 6, GPIO_ACTIVE_LOW), 162 GPIO_LOOKUP_IDX("dm355evm_msp", 7, NULL, 163 7, GPIO_ACTIVE_LOW), 164 { }, 165 }, 166}; 167 168#define MSP_GPIO_REG(offset) (msp_gpios[(offset)] >> 3) 169#define MSP_GPIO_MASK(offset) BIT(msp_gpios[(offset)] & 0x07) 170 171static int msp_gpio_in(struct gpio_chip *chip, unsigned offset) 172{ 173 switch (MSP_GPIO_REG(offset)) { 174 case DM355EVM_MSP_SWITCH1: 175 case DM355EVM_MSP_SWITCH2: 176 case DM355EVM_MSP_SDMMC: 177 return 0; 178 default: 179 return -EINVAL; 180 } 181} 182 183static u8 msp_led_cache; 184 185static int msp_gpio_get(struct gpio_chip *chip, unsigned offset) 186{ 187 int reg, status; 188 189 reg = MSP_GPIO_REG(offset); 190 status = dm355evm_msp_read(reg); 191 if (status < 0) 192 return status; 193 if (reg == DM355EVM_MSP_LED) 194 msp_led_cache = status; 195 return !!(status & MSP_GPIO_MASK(offset)); 196} 197 198static int msp_gpio_out(struct gpio_chip *chip, unsigned offset, int value) 199{ 200 int mask, bits; 201 202 /* NOTE: there are some other signals that could be 203 * packaged as output GPIOs, but they aren't as useful 204 * as the LEDs ... so for now we don't. 205 */ 206 if (MSP_GPIO_REG(offset) != DM355EVM_MSP_LED) 207 return -EINVAL; 208 209 mask = MSP_GPIO_MASK(offset); 210 bits = msp_led_cache; 211 212 bits &= ~mask; 213 if (value) 214 bits |= mask; 215 msp_led_cache = bits; 216 217 return dm355evm_msp_write(bits, DM355EVM_MSP_LED); 218} 219 220static void msp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 221{ 222 msp_gpio_out(chip, offset, value); 223} 224 225static struct gpio_chip dm355evm_msp_gpio = { 226 .label = "dm355evm_msp", 227 .owner = THIS_MODULE, 228 .direction_input = msp_gpio_in, 229 .get = msp_gpio_get, 230 .direction_output = msp_gpio_out, 231 .set = msp_gpio_set, 232 .base = -EINVAL, /* dynamic assignment */ 233 .ngpio = ARRAY_SIZE(msp_gpios), 234 .can_sleep = true, 235}; 236 237/*----------------------------------------------------------------------*/ 238 239static struct device *add_child(struct i2c_client *client, const char *name, 240 void *pdata, unsigned pdata_len, 241 bool can_wakeup, int irq) 242{ 243 struct platform_device *pdev; 244 int status; 245 246 pdev = platform_device_alloc(name, -1); 247 if (!pdev) 248 return ERR_PTR(-ENOMEM); 249 250 device_init_wakeup(&pdev->dev, can_wakeup); 251 pdev->dev.parent = &client->dev; 252 253 if (pdata) { 254 status = platform_device_add_data(pdev, pdata, pdata_len); 255 if (status < 0) { 256 dev_dbg(&pdev->dev, "can't add platform_data\n"); 257 goto put_device; 258 } 259 } 260 261 if (irq) { 262 struct resource r = { 263 .start = irq, 264 .flags = IORESOURCE_IRQ, 265 }; 266 267 status = platform_device_add_resources(pdev, &r, 1); 268 if (status < 0) { 269 dev_dbg(&pdev->dev, "can't add irq\n"); 270 goto put_device; 271 } 272 } 273 274 status = platform_device_add(pdev); 275 if (status) 276 goto put_device; 277 278 return &pdev->dev; 279 280put_device: 281 platform_device_put(pdev); 282 dev_err(&client->dev, "failed to add device %s\n", name); 283 return ERR_PTR(status); 284} 285 286static int add_children(struct i2c_client *client) 287{ 288 static const struct { 289 int offset; 290 char *label; 291 } config_inputs[] = { 292 /* 8 == right after the LEDs */ 293 { 8 + 0, "sw6_1", }, 294 { 8 + 1, "sw6_2", }, 295 { 8 + 2, "sw6_3", }, 296 { 8 + 3, "sw6_4", }, 297 { 8 + 4, "NTSC/nPAL", }, 298 }; 299 300 struct device *child; 301 int status; 302 int i; 303 304 /* GPIO-ish stuff */ 305 dm355evm_msp_gpio.parent = &client->dev; 306 status = gpiochip_add_data(&dm355evm_msp_gpio, NULL); 307 if (status < 0) 308 return status; 309 310 /* LED output */ 311 if (msp_has_leds()) { 312 gpiod_add_lookup_table(&evm_leds_gpio_table); 313 /* NOTE: these are the only fully programmable LEDs 314 * on the board, since GPIO-61/ds22 (and many signals 315 * going to DC7) must be used for AEMIF address lines 316 * unless the top 1 GB of NAND is unused... 317 */ 318 child = add_child(client, "leds-gpio", 319 &evm_led_data, sizeof(evm_led_data), 320 false, 0); 321 if (IS_ERR(child)) 322 return PTR_ERR(child); 323 } 324 325 /* configuration inputs */ 326 for (i = 0; i < ARRAY_SIZE(config_inputs); i++) { 327 int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset; 328 329 gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label); 330 331 /* make it easy for userspace to see these */ 332 gpio_export(gpio, false); 333 } 334 335 /* MMC/SD inputs -- right after the last config input */ 336 if (dev_get_platdata(&client->dev)) { 337 void (*mmcsd_setup)(unsigned) = dev_get_platdata(&client->dev); 338 339 mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5); 340 } 341 342 /* RTC is a 32 bit counter, no alarm */ 343 if (msp_has_rtc()) { 344 child = add_child(client, "rtc-dm355evm", 345 NULL, 0, false, 0); 346 if (IS_ERR(child)) 347 return PTR_ERR(child); 348 } 349 350 /* input from buttons and IR remote (uses the IRQ) */ 351 if (msp_has_keyboard()) { 352 child = add_child(client, "dm355evm_keys", 353 NULL, 0, true, client->irq); 354 if (IS_ERR(child)) 355 return PTR_ERR(child); 356 } 357 358 return 0; 359} 360 361/*----------------------------------------------------------------------*/ 362 363static void dm355evm_command(unsigned command) 364{ 365 int status; 366 367 status = dm355evm_msp_write(command, DM355EVM_MSP_COMMAND); 368 if (status < 0) 369 dev_err(&msp430->dev, "command %d failure %d\n", 370 command, status); 371} 372 373static void dm355evm_power_off(void) 374{ 375 dm355evm_command(MSP_COMMAND_POWEROFF); 376} 377 378static int dm355evm_msp_remove(struct i2c_client *client) 379{ 380 pm_power_off = NULL; 381 msp430 = NULL; 382 return 0; 383} 384 385static int 386dm355evm_msp_probe(struct i2c_client *client, const struct i2c_device_id *id) 387{ 388 int status; 389 const char *video = msp_has_tvp() ? "TVP5146" : "imager"; 390 391 if (msp430) 392 return -EBUSY; 393 msp430 = client; 394 395 /* display revision status; doubles as sanity check */ 396 status = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); 397 if (status < 0) 398 goto fail; 399 dev_info(&client->dev, "firmware v.%02X, %s as video-in\n", 400 status, video); 401 402 /* mux video input: either tvp5146 or some external imager */ 403 status = dm355evm_msp_write(msp_has_tvp() ? 0 : MSP_VIDEO_IMAGER, 404 DM355EVM_MSP_VIDEO_IN); 405 if (status < 0) 406 dev_warn(&client->dev, "error %d muxing %s as video-in\n", 407 status, video); 408 409 /* init LED cache, and turn off the LEDs */ 410 msp_led_cache = 0xff; 411 dm355evm_msp_write(msp_led_cache, DM355EVM_MSP_LED); 412 413 /* export capabilities we support */ 414 status = add_children(client); 415 if (status < 0) 416 goto fail; 417 418 /* PM hookup */ 419 pm_power_off = dm355evm_power_off; 420 421 return 0; 422 423fail: 424 /* FIXME remove children ... */ 425 dm355evm_msp_remove(client); 426 return status; 427} 428 429static const struct i2c_device_id dm355evm_msp_ids[] = { 430 { "dm355evm_msp", 0 }, 431 { /* end of list */ }, 432}; 433MODULE_DEVICE_TABLE(i2c, dm355evm_msp_ids); 434 435static struct i2c_driver dm355evm_msp_driver = { 436 .driver.name = "dm355evm_msp", 437 .id_table = dm355evm_msp_ids, 438 .probe = dm355evm_msp_probe, 439 .remove = dm355evm_msp_remove, 440}; 441 442static int __init dm355evm_msp_init(void) 443{ 444 return i2c_add_driver(&dm355evm_msp_driver); 445} 446subsys_initcall(dm355evm_msp_init); 447 448static void __exit dm355evm_msp_exit(void) 449{ 450 i2c_del_driver(&dm355evm_msp_driver); 451} 452module_exit(dm355evm_msp_exit); 453 454MODULE_DESCRIPTION("Interface to MSP430 firmware on DM355EVM"); 455MODULE_LICENSE("GPL");