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