1 From a607edde7251b573d84f7e0286d60138ecb5bc21 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Wed, 12 May 2010 14:22:36 +0200
4 Subject: [PATCH] Add n516 lpc driver
7 drivers/misc/Kconfig | 8 +
8 drivers/misc/Makefile | 1 +
9 drivers/misc/n516-lpc.c | 471 +++++++++++++++++++++++++++++++++++++++++++++++
10 3 files changed, 480 insertions(+), 0 deletions(-)
11 create mode 100644 drivers/misc/n516-lpc.c
13 --- a/drivers/misc/Kconfig
14 +++ b/drivers/misc/Kconfig
15 @@ -353,6 +353,14 @@ config VMWARE_BALLOON
16 To compile this driver as a module, choose M here: the
17 module will be called vmware_balloon.
20 + tristate "N516 keys & power controller"
23 + depends on POWER_SUPPLY
25 + N516 keyboard & power controller driver
27 source "drivers/misc/c2port/Kconfig"
28 source "drivers/misc/eeprom/Kconfig"
29 source "drivers/misc/cb710/Kconfig"
30 --- a/drivers/misc/Makefile
31 +++ b/drivers/misc/Makefile
32 @@ -31,3 +31,4 @@ obj-$(CONFIG_IWMC3200TOP) += iwmc32
35 obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o
36 +obj-$(CONFIG_N516_LPC) += n516-lpc.o
38 +++ b/drivers/misc/n516-lpc.c
40 +#include <linux/module.h>
41 +#include <linux/version.h>
42 +#include <linux/init.h>
43 +#include <linux/fs.h>
44 +#include <linux/interrupt.h>
45 +#include <linux/irq.h>
46 +#include <linux/sched.h>
47 +#include <linux/pm.h>
48 +#include <linux/sysctl.h>
49 +#include <linux/proc_fs.h>
50 +#include <linux/delay.h>
51 +#include <linux/platform_device.h>
52 +#include <linux/input.h>
53 +#include <linux/power_supply.h>
54 +#include <linux/suspend.h>
56 +#include <linux/i2c.h>
58 +#include <asm/mach-jz4740/irq.h>
59 +#include <asm/mach-jz4740/gpio.h>
60 +#include <asm/mach-jz4740/board-n516.h>
62 +static int batt_level=0;
63 +module_param(batt_level, int, 0);
65 +struct n516_lpc_chip {
66 + struct i2c_client *i2c_client;
67 + struct input_dev *input;
68 + unsigned int battery_level;
69 + unsigned int suspending:1, can_sleep:1;
72 +static struct n516_lpc_chip *the_lpc;
74 +struct i2c_device_id n516_lpc_i2c_ids[] = {
79 +MODULE_DEVICE_TABLE(i2c, n516_lpc_i2c_ids);
81 +static const unsigned short normal_i2c[] = I2C_ADDRS(0x54);
83 +static const unsigned int n516_lpc_keymap[] = {
94 + [0x0d] = KEY_PLAYPAUSE,
96 + [0x0f] = KEY_SEARCH,
97 + [0x10] = KEY_DIRECTION,
102 + [0x16] = KEY_RIGHT,
104 + [0x19] = KEY_PAGEDOWN,
105 + [0x1a] = KEY_PAGEUP,
106 + [0x1c] = KEY_POWER,
108 + [0x1e] = KEY_SLEEP,
109 + [0x1f] = KEY_WAKEUP,
112 +static const unsigned int batt_charge[] = {0, 7, 20, 45, 65, 80, 100};
113 +#define MAX_BAT_LEVEL 6
115 +static inline int n516_bat_charging(void)
117 + return !gpio_get_value(GPIO_CHARG_STAT_N);
120 +static int n516_bat_get_status(struct power_supply *b)
122 + if (power_supply_am_i_supplied(b)) {
123 + if (n516_bat_charging())
124 + return POWER_SUPPLY_STATUS_CHARGING;
126 + return POWER_SUPPLY_STATUS_FULL;
128 + return POWER_SUPPLY_STATUS_DISCHARGING;
132 +static int n516_bat_get_charge(struct power_supply *b)
134 + return batt_charge[the_lpc->battery_level];
137 +static int n516_bat_get_property(struct power_supply *b,
138 + enum power_supply_property psp,
139 + union power_supply_propval *val)
142 + case POWER_SUPPLY_PROP_STATUS:
143 + val->intval = n516_bat_get_status(b);
145 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
148 + case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
151 + case POWER_SUPPLY_PROP_CHARGE_NOW:
152 + val->intval = n516_bat_get_charge(b);
160 +static void n516_bat_power_changed(struct power_supply *p)
162 + if (power_supply_am_i_supplied(p) && !n516_bat_charging())
163 + the_lpc->battery_level = MAX_BAT_LEVEL;
165 + power_supply_changed(p);
168 +static enum power_supply_property n516_bat_properties[] = {
169 + POWER_SUPPLY_PROP_STATUS,
170 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
171 + POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
172 + POWER_SUPPLY_PROP_CHARGE_NOW,
175 +static struct power_supply n516_battery = {
176 + .name = "n516-battery",
177 + .get_property = n516_bat_get_property,
178 + .properties = n516_bat_properties,
179 + .num_properties = ARRAY_SIZE(n516_bat_properties),
180 + .external_power_changed = n516_bat_power_changed,
183 +static irqreturn_t n516_bat_charge_irq(int irq, void *dev)
185 + struct power_supply *psy = dev;
187 + dev_dbg(psy->dev, "Battery charging IRQ\n");
189 + if (power_supply_am_i_supplied(psy) && !n516_bat_charging())
190 + the_lpc->battery_level = MAX_BAT_LEVEL;
192 + power_supply_changed(psy);
194 + return IRQ_HANDLED;
197 +static int n516_lpc_send_message(struct n516_lpc_chip *chip, unsigned char val)
199 + struct i2c_client *client = chip->i2c_client;
200 + struct i2c_msg msg = {client->addr, client->flags, 1, &val};
203 + ret = i2c_transfer(client->adapter, &msg, 1);
204 + return ret > 0 ? 0 : ret;
207 +static void n516_key_event(struct n516_lpc_chip *chip, unsigned char keycode)
209 + struct i2c_client *client = chip->i2c_client;
210 + bool long_press = false;
212 + if (keycode & 0x40) {
217 + dev_dbg(&client->dev, "keycode: 0x%02x, long_press: 0x%02x\n", keycode, (unsigned int)long_press);
219 + if (keycode >= ARRAY_SIZE(n516_lpc_keymap) || n516_lpc_keymap[keycode] == 0)
223 + input_report_key(chip->input, KEY_LEFTALT, 1);
225 + input_report_key(chip->input, n516_lpc_keymap[keycode], 1);
226 + input_sync(chip->input);
227 + input_report_key(chip->input, n516_lpc_keymap[keycode], 0);
230 + input_report_key(chip->input, KEY_LEFTALT, 0);
231 + input_sync(chip->input);
234 +static void n516_battery_event(struct n516_lpc_chip *chip, unsigned char battery_level)
236 + if (battery_level != chip->battery_level) {
237 + chip->battery_level = battery_level;
238 + power_supply_changed(&n516_battery);
242 +static irqreturn_t n516_lpc_irq_thread(int irq, void *devid)
244 + struct n516_lpc_chip *chip = (struct n516_lpc_chip*)devid;
246 + unsigned char raw_msg;
247 + struct i2c_client *client = chip->i2c_client;
248 + struct i2c_msg msg = {client->addr, client->flags | I2C_M_RD, 1, &raw_msg};
250 + if (client->dev.power.status >= DPM_OFF)
251 + return IRQ_HANDLED;
253 + ret = i2c_transfer(client->adapter, &msg, 1);
255 + dev_dbg(&client->dev, "I2C error: %d\n", ret);
256 + return IRQ_HANDLED;
259 + dev_dbg(&client->dev, "msg: 0x%02x\n", raw_msg);
261 + /* Ack wakeup event */
262 + if ((raw_msg & ~0x40) < ARRAY_SIZE(n516_lpc_keymap))
263 + n516_key_event(chip, raw_msg);
264 + else if ((raw_msg >= 0x81) && (raw_msg <= 0x87))
265 + n516_battery_event(chip, raw_msg - 0x81);
266 + else if (raw_msg == 0x7e)
267 + n516_lpc_send_message(chip, 0x00);
269 + dev_warn(&client->dev, "Unknown message: %x\n", raw_msg);
271 + if (chip->suspending)
272 + chip->can_sleep = 0;
274 + return IRQ_HANDLED;
277 +static void n516_lpc_power_off(void)
279 + struct i2c_client *client = the_lpc->i2c_client;
280 + unsigned char val = 0x01;
281 + struct i2c_msg msg = {client->addr, client->flags, 1, &val};
283 + printk("Issue LPC POWEROFF command...\n");
285 + i2c_transfer(client->adapter, &msg, 1);
288 +static int n516_lpc_detect(struct i2c_client *client, struct i2c_board_info *info)
293 +static int n516_lpc_suspend_notifier(struct notifier_block *nb,
294 + unsigned long event,
298 + case PM_SUSPEND_PREPARE:
299 + the_lpc->suspending = 1;
300 + the_lpc->can_sleep = 1;
302 + case PM_POST_SUSPEND:
303 + the_lpc->suspending = 0;
304 + the_lpc->can_sleep = 1;
307 + return NOTIFY_DONE;
312 +static struct notifier_block n516_lpc_notif_block = {
313 + .notifier_call = n516_lpc_suspend_notifier,
316 +static int __devinit n516_lpc_probe(struct i2c_client *client, const struct i2c_device_id *id)
318 + struct n516_lpc_chip *chip;
319 + struct input_dev *input;
323 + chip = kzalloc(sizeof(*chip), GFP_KERNEL);
328 + chip->i2c_client = client;
329 + if ((batt_level > 0) && (batt_level < ARRAY_SIZE(batt_charge)))
330 + chip->battery_level = batt_level;
332 + chip->battery_level = 1;
334 + i2c_set_clientdata(client, chip);
336 + ret = gpio_request(GPIO_LPC_INT, "LPC interrupt request");
338 + dev_err(&client->dev, "Unable to reguest LPC INT GPIO\n");
339 + goto err_gpio_req_lpcint;
342 + ret = gpio_request(GPIO_CHARG_STAT_N, "LPC charging status");
344 + dev_err(&client->dev, "Unable to reguest CHARG STAT GPIO\n");
345 + goto err_gpio_req_chargstat;
348 + /* Enter normal mode */
349 + n516_lpc_send_message(chip, 0x2);
351 + input = input_allocate_device();
353 + dev_err(&client->dev, "Unable to allocate input device\n");
355 + goto err_input_alloc;
358 + chip->input = input;
360 + __set_bit(EV_KEY, input->evbit);
362 + for (i = 0; i < ARRAY_SIZE(n516_lpc_keymap); i++)
363 + __set_bit(n516_lpc_keymap[i], input->keybit);
365 + __set_bit(KEY_LEFTALT, input->keybit);
367 + input->name = "n516-keys";
368 + input->phys = "n516-keys/input0";
369 + input->dev.parent = &client->dev;
370 + input->id.bustype = BUS_I2C;
371 + input->id.vendor = 0x0001;
372 + input->id.product = 0x0001;
373 + input->id.version = 0x0100;
375 + ret = input_register_device(input);
377 + dev_err(&client->dev, "Unable to register input device\n");
378 + goto err_input_register;
381 + ret = power_supply_register(NULL, &n516_battery);
383 + dev_err(&client->dev, "Unable to register N516 battery\n");
387 + ret = request_threaded_irq(gpio_to_irq(GPIO_LPC_INT), NULL,
388 + n516_lpc_irq_thread,
389 + IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
392 + dev_err(&client->dev, "request_irq failed: %d\n", ret);
393 + goto err_request_lpc_irq;
396 + ret = request_irq(gpio_to_irq(GPIO_CHARG_STAT_N), n516_bat_charge_irq,
397 + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
398 + "battery charging", &n516_battery);
400 + dev_err(&client->dev, "Unable to claim battery charging IRQ\n");
401 + goto err_request_chrg_irq;
404 + pm_power_off = n516_lpc_power_off;
405 + ret = register_pm_notifier(&n516_lpc_notif_block);
407 + dev_err(&client->dev, "Unable to register PM notify block\n");
408 + goto err_reg_pm_notifier;
411 + device_init_wakeup(&client->dev, 1);
415 + unregister_pm_notifier(&n516_lpc_notif_block);
416 +err_reg_pm_notifier:
417 + free_irq(gpio_to_irq(GPIO_CHARG_STAT_N), &n516_battery);
418 +err_request_chrg_irq:
419 + free_irq(gpio_to_irq(GPIO_LPC_INT), chip);
420 +err_request_lpc_irq:
421 + power_supply_unregister(&n516_battery);
423 + input_unregister_device(input);
425 + input_free_device(input);
427 + gpio_free(GPIO_CHARG_STAT_N);
428 +err_gpio_req_chargstat:
429 + gpio_free(GPIO_LPC_INT);
430 +err_gpio_req_lpcint:
431 + i2c_set_clientdata(client, NULL);
437 +static int __devexit n516_lpc_remove(struct i2c_client *client)
439 + struct n516_lpc_chip *chip = i2c_get_clientdata(client);
441 + unregister_pm_notifier(&n516_lpc_notif_block);
442 + pm_power_off = NULL;
443 + free_irq(gpio_to_irq(GPIO_CHARG_STAT_N), &n516_battery);
444 + free_irq(gpio_to_irq(GPIO_LPC_INT), chip);
445 + power_supply_unregister(&n516_battery);
446 + input_unregister_device(chip->input);
447 + gpio_free(GPIO_CHARG_STAT_N);
448 + gpio_free(GPIO_LPC_INT);
449 + i2c_set_clientdata(client, NULL);
456 +static int n516_lpc_suspend(struct i2c_client *client, pm_message_t msg)
458 + if (!the_lpc->can_sleep)
461 + if (device_may_wakeup(&client->dev))
462 + enable_irq_wake(gpio_to_irq(GPIO_LPC_INT));
467 +static int n516_lpc_resume(struct i2c_client *client)
469 + if (device_may_wakeup(&client->dev))
470 + disable_irq_wake(gpio_to_irq(GPIO_LPC_INT));
475 +#define n516_lpc_suspend NULL
476 +#define n516_lpc_resume NULL
480 +static struct i2c_driver n516_lpc_driver = {
481 + .class = I2C_CLASS_HWMON,
483 + .name = "n516-keys",
484 + .owner = THIS_MODULE,
486 + .probe = n516_lpc_probe,
487 + .remove = __devexit_p(n516_lpc_remove),
488 + .detect = n516_lpc_detect,
489 + .id_table = n516_lpc_i2c_ids,
490 + .address_list = normal_i2c,
491 + .suspend = n516_lpc_suspend,
492 + .resume = n516_lpc_resume,
495 +static int __init n516_lpc_init(void)
497 + return i2c_add_driver(&n516_lpc_driver);
499 +module_init(n516_lpc_init);
501 +static void __exit n516_lpc_exit(void)
503 + i2c_del_driver(&n516_lpc_driver);
505 +module_exit(n516_lpc_exit);
507 +MODULE_AUTHOR("Yauhen Kharuzhy");
508 +MODULE_LICENSE("GPL");
509 +MODULE_DESCRIPTION("Keys and power controller driver for N516");
510 +MODULE_ALIAS("platform:n516-keys");