| 1 | /* |
| 2 | * arch/ubicom32/mach-common/ubicom32hid.c |
| 3 | * I2C driver for HID coprocessor found on some DPF implementations. |
| 4 | * |
| 5 | * (C) Copyright 2009, Ubicom, Inc. |
| 6 | * |
| 7 | * This file is part of the Ubicom32 Linux Kernel Port. |
| 8 | * |
| 9 | * The Ubicom32 Linux Kernel Port is free software: you can redistribute |
| 10 | * it and/or modify it under the terms of the GNU General Public License |
| 11 | * as published by the Free Software Foundation, either version 2 of the |
| 12 | * License, or (at your option) any later version. |
| 13 | * |
| 14 | * The Ubicom32 Linux Kernel Port is distributed in the hope that it |
| 15 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
| 16 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| 17 | * the GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with the Ubicom32 Linux Kernel Port. If not, |
| 21 | * see <http://www.gnu.org/licenses/>. |
| 22 | * |
| 23 | * Ubicom32 implementation derived from (with many thanks): |
| 24 | * arch/m68knommu |
| 25 | * arch/blackfin |
| 26 | * arch/parisc |
| 27 | */ |
| 28 | |
| 29 | #include <linux/module.h> |
| 30 | #include <linux/init.h> |
| 31 | #include <linux/gpio.h> |
| 32 | #include <linux/delay.h> |
| 33 | #include <linux/platform_device.h> |
| 34 | #include <linux/i2c.h> |
| 35 | #include <linux/backlight.h> |
| 36 | #include <linux/fb.h> |
| 37 | #include <linux/input.h> |
| 38 | #include <linux/input-polldev.h> |
| 39 | |
| 40 | #include <asm/ubicom32hid.h> |
| 41 | |
| 42 | #define DRIVER_NAME "ubicom32hid" |
| 43 | |
| 44 | #ifdef DEBUG |
| 45 | static int ubicom32hid_debug; |
| 46 | #endif |
| 47 | |
| 48 | static const struct i2c_device_id ubicom32hid_id[] = { |
| 49 | { DRIVER_NAME, }, |
| 50 | { } |
| 51 | }; |
| 52 | MODULE_DEVICE_TABLE(i2c, ubicom32hid_id); |
| 53 | |
| 54 | /* |
| 55 | * Define this to make IR checking strict, in general, it's not needed |
| 56 | */ |
| 57 | #undef UBICOM32HID_STRICT_IR_CHECK |
| 58 | |
| 59 | #define UBICOM32HID_CMD_SET_PWM 0x01 |
| 60 | #define UBICOM32HID_CMD_SET_BL_EN 0x02 |
| 61 | #define UBICOM32HID_BL_EN_LOW 0x00 |
| 62 | #define UBICOM32HID_BL_EN_HIZ 0x01 |
| 63 | #define UBICOM32HID_BL_EN_HI 0x02 |
| 64 | #define UBICOM32HID_CMD_FLUSH 0x99 |
| 65 | #define UBICOM32HID_CMD_RESET 0x99 |
| 66 | #define UBICOM32HID_CMD_GET_IR_SWITCH 0xC0 |
| 67 | #define UBICOM32HID_CMD_GET_REVISION 0xfd |
| 68 | #define UBICOM32HID_CMD_GET_DEVICE_ID 0xfe |
| 69 | #define UBICOM32HID_CMD_GET_VERSION 0xff |
| 70 | #define UBICOM32HID_DEVICE_ID 0x49 |
| 71 | |
| 72 | #define UBICOM32HID_MAX_BRIGHTNESS_PWM 255 |
| 73 | |
| 74 | /* |
| 75 | * Data structure returned by the HID device |
| 76 | */ |
| 77 | struct ubicom32hid_input_data { |
| 78 | uint32_t ircmd; |
| 79 | uint8_t sw_state; |
| 80 | uint8_t sw_changed; |
| 81 | }; |
| 82 | |
| 83 | /* |
| 84 | * Our private data |
| 85 | */ |
| 86 | struct ubicom32hid_data { |
| 87 | /* |
| 88 | * Pointer to the platform data structure, we need the settings. |
| 89 | */ |
| 90 | const struct ubicom32hid_platform_data *pdata; |
| 91 | |
| 92 | /* |
| 93 | * Backlight device |
| 94 | */ |
| 95 | struct backlight_device *bldev; |
| 96 | |
| 97 | /* |
| 98 | * I2C client, for sending messages to the HID device |
| 99 | */ |
| 100 | struct i2c_client *client; |
| 101 | |
| 102 | /* |
| 103 | * Current intensity, used for get_intensity. |
| 104 | */ |
| 105 | int cur_intensity; |
| 106 | |
| 107 | /* |
| 108 | * Input subsystem |
| 109 | * We won't register an input subsystem if there are no mappings. |
| 110 | */ |
| 111 | struct input_polled_dev *poll_dev; |
| 112 | }; |
| 113 | |
| 114 | |
| 115 | /* |
| 116 | * ubicom32hid_set_intensity |
| 117 | */ |
| 118 | static int ubicom32hid_set_intensity(struct backlight_device *bd) |
| 119 | { |
| 120 | struct ubicom32hid_data *ud = |
| 121 | (struct ubicom32hid_data *)bl_get_data(bd); |
| 122 | int intensity = bd->props.brightness; |
| 123 | int reg; |
| 124 | u8_t val; |
| 125 | int ret; |
| 126 | |
| 127 | /* |
| 128 | * If we're blanked the the intensity doesn't matter. |
| 129 | */ |
| 130 | if ((bd->props.power != FB_BLANK_UNBLANK) || |
| 131 | (bd->props.fb_blank != FB_BLANK_UNBLANK)) { |
| 132 | intensity = 0; |
| 133 | } |
| 134 | |
| 135 | /* |
| 136 | * Set the brightness based on the type of backlight |
| 137 | */ |
| 138 | if (ud->pdata->type == UBICOM32HID_BL_TYPE_BINARY) { |
| 139 | reg = UBICOM32HID_CMD_SET_BL_EN; |
| 140 | if (intensity) { |
| 141 | val = ud->pdata->invert |
| 142 | ? UBICOM32HID_BL_EN_LOW : UBICOM32HID_BL_EN_HI; |
| 143 | } else { |
| 144 | val = ud->pdata->invert |
| 145 | ? UBICOM32HID_BL_EN_HI : UBICOM32HID_BL_EN_LOW; |
| 146 | } |
| 147 | } else { |
| 148 | reg = UBICOM32HID_CMD_SET_PWM; |
| 149 | val = ud->pdata->invert |
| 150 | ? (UBICOM32HID_MAX_BRIGHTNESS_PWM - intensity) : |
| 151 | intensity; |
| 152 | } |
| 153 | |
| 154 | /* |
| 155 | * Send the command |
| 156 | */ |
| 157 | ret = i2c_smbus_write_byte_data(ud->client, reg, val); |
| 158 | if (ret < 0) { |
| 159 | dev_warn(&ud->client->dev, "Unable to write backlight err=%d\n", |
| 160 | ret); |
| 161 | return ret; |
| 162 | } |
| 163 | |
| 164 | ud->cur_intensity = intensity; |
| 165 | |
| 166 | return 0; |
| 167 | } |
| 168 | |
| 169 | /* |
| 170 | * ubicom32hid_get_intensity |
| 171 | * Return the current intensity of the backlight. |
| 172 | */ |
| 173 | static int ubicom32hid_get_intensity(struct backlight_device *bd) |
| 174 | { |
| 175 | struct ubicom32hid_data *ud = |
| 176 | (struct ubicom32hid_data *)bl_get_data(bd); |
| 177 | |
| 178 | return ud->cur_intensity; |
| 179 | } |
| 180 | |
| 181 | /* |
| 182 | * ubicom32hid_verify_data |
| 183 | * Verify the data to see if there is any action to be taken |
| 184 | * |
| 185 | * Returns 0 if no action is to be taken, non-zero otherwise |
| 186 | */ |
| 187 | static int ubicom32hid_verify_data(struct ubicom32hid_data *ud, |
| 188 | struct ubicom32hid_input_data *data) |
| 189 | { |
| 190 | uint8_t *ircmd = (uint8_t *)&(data->ircmd); |
| 191 | |
| 192 | /* |
| 193 | * ircmd == DEADBEEF means ir queue is empty. Since this is a |
| 194 | * meaningful code, that means the rest of the message is most likely |
| 195 | * correct, so only process the data if the switch state has changed. |
| 196 | */ |
| 197 | if (data->ircmd == 0xDEADBEEF) { |
| 198 | return data->sw_changed != 0; |
| 199 | } |
| 200 | |
| 201 | /* |
| 202 | * We have an ircmd which is not empty: |
| 203 | * Data[1] should be the complement of Data[0] |
| 204 | */ |
| 205 | if (ircmd[0] != (u8_t)~ircmd[1]) { |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | #ifdef UBICOM32HID_STRICT_IR_CHECK |
| 210 | /* |
| 211 | * It seems that some remote controls don't follow the NEC protocol |
| 212 | * properly, so only do this check if the remote does indeed follow the |
| 213 | * spec. Data[3] should be the complement of Data[2] |
| 214 | */ |
| 215 | if (ircmd[2] == (u8_t)~ircmd[3]) { |
| 216 | return 1; |
| 217 | } |
| 218 | |
| 219 | /* |
| 220 | * For non-compliant remotes, check the system code according to what |
| 221 | * they send. |
| 222 | */ |
| 223 | if ((ircmd[2] != UBICOM32HID_IR_SYSTEM_CODE_CHECK) || |
| 224 | (ircmd[3] != UBICOM32HID_IR_SYSTEM_CODE)) { |
| 225 | return 0; |
| 226 | } |
| 227 | #endif |
| 228 | |
| 229 | /* |
| 230 | * Data checks out, process |
| 231 | */ |
| 232 | return 1; |
| 233 | } |
| 234 | |
| 235 | /* |
| 236 | * ubicom32hid_poll_input |
| 237 | * Poll the input from the HID device. |
| 238 | */ |
| 239 | static void ubicom32hid_poll_input(struct input_polled_dev *dev) |
| 240 | { |
| 241 | struct ubicom32hid_data *ud = (struct ubicom32hid_data *)dev->private; |
| 242 | const struct ubicom32hid_platform_data *pdata = ud->pdata; |
| 243 | struct ubicom32hid_input_data data; |
| 244 | struct input_dev *id = dev->input; |
| 245 | int i; |
| 246 | int sync_needed = 0; |
| 247 | uint8_t cmd; |
| 248 | int ret; |
| 249 | |
| 250 | /* |
| 251 | * Flush the queue |
| 252 | */ |
| 253 | cmd = UBICOM32HID_CMD_FLUSH; |
| 254 | ret = i2c_master_send(ud->client, &cmd, 1); |
| 255 | if (ret < 0) { |
| 256 | return; |
| 257 | } |
| 258 | |
| 259 | ret = i2c_smbus_read_i2c_block_data( |
| 260 | ud->client, UBICOM32HID_CMD_GET_IR_SWITCH, 6, (void *)&data); |
| 261 | if (ret < 0) { |
| 262 | return; |
| 263 | } |
| 264 | |
| 265 | /* |
| 266 | * Verify the data to see if there is any action to be taken |
| 267 | */ |
| 268 | if (!ubicom32hid_verify_data(ud, &data)) { |
| 269 | return; |
| 270 | } |
| 271 | |
| 272 | #ifdef DEBUG |
| 273 | if (ubicom32hid_debug) { |
| 274 | printk("Polled ircmd=%8x swstate=%2x swchanged=%2x\n", |
| 275 | data.ircmd, data.sw_state, data.sw_changed); |
| 276 | } |
| 277 | #endif |
| 278 | |
| 279 | /* |
| 280 | * Process changed switches |
| 281 | */ |
| 282 | if (data.sw_changed) { |
| 283 | const struct ubicom32hid_button *ub = pdata->buttons; |
| 284 | for (i = 0; i < pdata->nbuttons; i++, ub++) { |
| 285 | uint8_t mask = (1 << ub->bit); |
| 286 | if (!(data.sw_changed & mask)) { |
| 287 | continue; |
| 288 | } |
| 289 | |
| 290 | sync_needed = 1; |
| 291 | input_event(id, ub->type, ub->code, |
| 292 | (data.sw_state & mask) ? 1 : 0); |
| 293 | } |
| 294 | } |
| 295 | if (sync_needed) { |
| 296 | input_sync(id); |
| 297 | } |
| 298 | |
| 299 | /* |
| 300 | * Process ir codes |
| 301 | */ |
| 302 | if (data.ircmd != 0xDEADBEEF) { |
| 303 | const struct ubicom32hid_ir *ui = pdata->ircodes; |
| 304 | for (i = 0; i < pdata->nircodes; i++, ui++) { |
| 305 | if (ui->ir_code == data.ircmd) { |
| 306 | /* |
| 307 | * Simulate a up/down event |
| 308 | */ |
| 309 | input_event(id, ui->type, ui->code, 1); |
| 310 | input_sync(id); |
| 311 | input_event(id, ui->type, ui->code, 0); |
| 312 | input_sync(id); |
| 313 | } |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | |
| 319 | /* |
| 320 | * Backlight ops |
| 321 | */ |
| 322 | static struct backlight_ops ubicom32hid_blops = { |
| 323 | .get_brightness = ubicom32hid_get_intensity, |
| 324 | .update_status = ubicom32hid_set_intensity, |
| 325 | }; |
| 326 | |
| 327 | /* |
| 328 | * ubicom32hid_probe |
| 329 | */ |
| 330 | static int ubicom32hid_probe(struct i2c_client *client, |
| 331 | const struct i2c_device_id *id) |
| 332 | { |
| 333 | struct ubicom32hid_platform_data *pdata; |
| 334 | struct ubicom32hid_data *ud; |
| 335 | int ret; |
| 336 | int i; |
| 337 | u8 version[2]; |
| 338 | char buf[1]; |
| 339 | |
| 340 | pdata = client->dev.platform_data; |
| 341 | if (pdata == NULL) { |
| 342 | return -ENODEV; |
| 343 | } |
| 344 | |
| 345 | /* |
| 346 | * See if we even have a device available before allocating memory. |
| 347 | * |
| 348 | * Hard reset the device |
| 349 | */ |
| 350 | ret = gpio_request(pdata->gpio_reset, "ubicom32hid-reset"); |
| 351 | if (ret < 0) { |
| 352 | return ret; |
| 353 | } |
| 354 | gpio_direction_output(pdata->gpio_reset, pdata->gpio_reset_polarity); |
| 355 | udelay(100); |
| 356 | gpio_set_value(pdata->gpio_reset, !pdata->gpio_reset_polarity); |
| 357 | udelay(100); |
| 358 | |
| 359 | /* |
| 360 | * soft reset the device. It sometimes takes a while to do this. |
| 361 | */ |
| 362 | for (i = 0; i < 50; i++) { |
| 363 | buf[0] = UBICOM32HID_CMD_RESET; |
| 364 | ret = i2c_master_send(client, buf, 1); |
| 365 | if (ret > 0) { |
| 366 | break; |
| 367 | } |
| 368 | udelay(10000); |
| 369 | } |
| 370 | if (i == 50) { |
| 371 | dev_warn(&client->dev, "Unable to reset device\n"); |
| 372 | goto fail; |
| 373 | } |
| 374 | |
| 375 | ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_DEVICE_ID); |
| 376 | if (ret != UBICOM32HID_DEVICE_ID) { |
| 377 | dev_warn(&client->dev, "Incorrect device id %02x\n", buf[0]); |
| 378 | ret = -ENODEV; |
| 379 | goto fail; |
| 380 | } |
| 381 | |
| 382 | ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_VERSION); |
| 383 | if (ret < 0) { |
| 384 | dev_warn(&client->dev, "Unable to get version\n"); |
| 385 | goto fail; |
| 386 | } |
| 387 | version[0] = ret; |
| 388 | |
| 389 | ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_REVISION); |
| 390 | if (ret < 0) { |
| 391 | dev_warn(&client->dev, "Unable to get revision\n"); |
| 392 | goto fail; |
| 393 | } |
| 394 | version[1] = ret; |
| 395 | |
| 396 | /* |
| 397 | * Allocate our private data |
| 398 | */ |
| 399 | ud = kzalloc(sizeof(struct ubicom32hid_data), GFP_KERNEL); |
| 400 | if (!ud) { |
| 401 | ret = -ENOMEM; |
| 402 | goto fail; |
| 403 | } |
| 404 | ud->pdata = pdata; |
| 405 | ud->client = client; |
| 406 | |
| 407 | /* |
| 408 | * Register our backlight device |
| 409 | */ |
| 410 | ud->bldev = backlight_device_register(DRIVER_NAME, &client->dev, |
| 411 | ud, &ubicom32hid_blops); |
| 412 | if (IS_ERR(ud->bldev)) { |
| 413 | ret = PTR_ERR(ud->bldev); |
| 414 | goto fail2; |
| 415 | } |
| 416 | platform_set_drvdata(client, ud); |
| 417 | |
| 418 | /* |
| 419 | * Start up the backlight with the requested intensity |
| 420 | */ |
| 421 | ud->bldev->props.power = FB_BLANK_UNBLANK; |
| 422 | ud->bldev->props.max_brightness = |
| 423 | (pdata->type == UBICOM32HID_BL_TYPE_PWM) ? |
| 424 | UBICOM32HID_MAX_BRIGHTNESS_PWM : 1; |
| 425 | if (pdata->default_intensity < ud->bldev->props.max_brightness) { |
| 426 | ud->bldev->props.brightness = pdata->default_intensity; |
| 427 | } else { |
| 428 | dev_warn(&client->dev, "Default brightness out of range, " |
| 429 | "setting to max\n"); |
| 430 | ud->bldev->props.brightness = ud->bldev->props.max_brightness; |
| 431 | } |
| 432 | |
| 433 | ubicom32hid_set_intensity(ud->bldev); |
| 434 | |
| 435 | /* |
| 436 | * Check to see if we have any inputs |
| 437 | */ |
| 438 | if (!pdata->nbuttons && !pdata->nircodes) { |
| 439 | goto done; |
| 440 | } |
| 441 | |
| 442 | /* |
| 443 | * We have buttons or codes, we must register an input device |
| 444 | */ |
| 445 | ud->poll_dev = input_allocate_polled_device(); |
| 446 | if (!ud->poll_dev) { |
| 447 | ret = -ENOMEM; |
| 448 | goto fail3; |
| 449 | } |
| 450 | |
| 451 | /* |
| 452 | * Setup the polling to default to 100ms |
| 453 | */ |
| 454 | ud->poll_dev->poll = ubicom32hid_poll_input; |
| 455 | ud->poll_dev->poll_interval = |
| 456 | pdata->poll_interval ? pdata->poll_interval : 100; |
| 457 | ud->poll_dev->private = ud; |
| 458 | |
| 459 | ud->poll_dev->input->name = |
| 460 | pdata->input_name ? pdata->input_name : "Ubicom32HID"; |
| 461 | ud->poll_dev->input->phys = "ubicom32hid/input0"; |
| 462 | ud->poll_dev->input->dev.parent = &client->dev; |
| 463 | ud->poll_dev->input->id.bustype = BUS_I2C; |
| 464 | |
| 465 | /* |
| 466 | * Set the capabilities by running through the buttons and ir codes |
| 467 | */ |
| 468 | for (i = 0; i < pdata->nbuttons; i++) { |
| 469 | const struct ubicom32hid_button *ub = &pdata->buttons[i]; |
| 470 | |
| 471 | input_set_capability(ud->poll_dev->input, |
| 472 | ub->type ? ub->type : EV_KEY, ub->code); |
| 473 | } |
| 474 | |
| 475 | for (i = 0; i < pdata->nircodes; i++) { |
| 476 | const struct ubicom32hid_ir *ui = &pdata->ircodes[i]; |
| 477 | |
| 478 | input_set_capability(ud->poll_dev->input, |
| 479 | ui->type ? ui->type : EV_KEY, ui->code); |
| 480 | } |
| 481 | |
| 482 | ret = input_register_polled_device(ud->poll_dev); |
| 483 | if (ret) { |
| 484 | goto fail3; |
| 485 | } |
| 486 | |
| 487 | done: |
| 488 | printk(KERN_INFO DRIVER_NAME ": enabled, version=%02x.%02x\n", |
| 489 | version[0], version[1]); |
| 490 | |
| 491 | return 0; |
| 492 | |
| 493 | fail3: |
| 494 | gpio_free(ud->pdata->gpio_reset); |
| 495 | backlight_device_unregister(ud->bldev); |
| 496 | fail2: |
| 497 | kfree(ud); |
| 498 | fail: |
| 499 | gpio_free(pdata->gpio_reset); |
| 500 | return ret; |
| 501 | } |
| 502 | |
| 503 | /* |
| 504 | * ubicom32hid_remove |
| 505 | */ |
| 506 | static int ubicom32hid_remove(struct i2c_client *client) |
| 507 | { |
| 508 | struct ubicom32hid_data *ud = |
| 509 | (struct ubicom32hid_data *)platform_get_drvdata(client); |
| 510 | |
| 511 | gpio_free(ud->pdata->gpio_reset); |
| 512 | |
| 513 | backlight_device_unregister(ud->bldev); |
| 514 | |
| 515 | if (ud->poll_dev) { |
| 516 | input_unregister_polled_device(ud->poll_dev); |
| 517 | input_free_polled_device(ud->poll_dev); |
| 518 | } |
| 519 | |
| 520 | platform_set_drvdata(client, NULL); |
| 521 | |
| 522 | kfree(ud); |
| 523 | |
| 524 | return 0; |
| 525 | } |
| 526 | |
| 527 | static struct i2c_driver ubicom32hid_driver = { |
| 528 | .driver = { |
| 529 | .name = DRIVER_NAME, |
| 530 | .owner = THIS_MODULE, |
| 531 | }, |
| 532 | .probe = ubicom32hid_probe, |
| 533 | .remove = __exit_p(ubicom32hid_remove), |
| 534 | .id_table = ubicom32hid_id, |
| 535 | }; |
| 536 | |
| 537 | /* |
| 538 | * ubicom32hid_init |
| 539 | */ |
| 540 | static int __init ubicom32hid_init(void) |
| 541 | { |
| 542 | return i2c_add_driver(&ubicom32hid_driver); |
| 543 | } |
| 544 | module_init(ubicom32hid_init); |
| 545 | |
| 546 | /* |
| 547 | * ubicom32hid_exit |
| 548 | */ |
| 549 | static void __exit ubicom32hid_exit(void) |
| 550 | { |
| 551 | i2c_del_driver(&ubicom32hid_driver); |
| 552 | } |
| 553 | module_exit(ubicom32hid_exit); |
| 554 | |
| 555 | MODULE_AUTHOR("Pat Tjin <@ubicom.com>") |
| 556 | MODULE_DESCRIPTION("Ubicom HID driver"); |
| 557 | MODULE_LICENSE("GPL"); |
| 558 | |