From a4206db79f31ef860367a2dac31583f517ebfd91 Mon Sep 17 00:00:00 2001 From: Markinus Date: Sat, 28 Aug 2010 10:49:07 +0200 Subject: [PATCH] htcleo: add keypad driver Incl. keypad LED --- arch/arm/mach-msm/Makefile | 3 +- arch/arm/mach-msm/board-htcleo-keypad.c | 231 ++++++++++++++++++++++++ 2 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/board-htcleo-keypad.c diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 56d54188..8a09804d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -99,7 +99,8 @@ obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-rfkill.o board-bravoc-audio.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-wifi.o htc_awb_cal.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o clock.o -obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-spi.o board-htcleo-panel.o clock-wince.o +obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-spi.o board-htcleo-panel.o board-htcleo-keypad.o +obj-$(CONFIG_MACH_HTCLEO) += clock-wince.o # MSM7x30 boards obj-$(CONFIG_ARCH_MSM7X30) += panel-samsungwvga-tl2796a.o panel-samsungwvga-s6e63m0.o panel-sonywvga-s6d16a0x21-7x30.o diff --git a/arch/arm/mach-msm/board-htcleo-keypad.c b/arch/arm/mach-msm/board-htcleo-keypad.c new file mode 100644 index 00000000..085386bc --- /dev/null +++ b/arch/arm/mach-msm/board-htcleo-keypad.c @@ -0,0 +1,231 @@ +/* arch/arm/mach-msm/board-htcleo-keypad.c + * + * Author: Markinus + * Author: Parad0X + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "board-htcleo.h" + +struct led_data { + struct led_classdev ldev; + struct mutex led_data_mutex; + struct work_struct brightness_work; + spinlock_t brightness_lock; + enum led_brightness brightness; + uint8_t oldval; +} keypad_led_data; + + +static unsigned int htcleo_col_gpios[] = { + HTCLEO_GPIO_KP_MKOUT0, + HTCLEO_GPIO_KP_MKOUT1, + HTCLEO_GPIO_KP_MKOUT2 +}; + +static unsigned int htcleo_row_gpios[] = { + HTCLEO_GPIO_KP_MPIN0, + HTCLEO_GPIO_KP_MPIN1, + HTCLEO_GPIO_KP_MPIN2 +}; + +#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(htcleo_row_gpios) + (row)) +#define KEYMAP_SIZE (ARRAY_SIZE(htcleo_col_gpios) * \ + ARRAY_SIZE(htcleo_row_gpios)) + +/* keypad */ +static const unsigned short htcleo_keymap[KEYMAP_SIZE] = { + [KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP, + [KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(1, 0)] = KEY_MENU, // Windows Button + [KEYMAP_INDEX(1, 1)] = KEY_SEND, // Green Button + [KEYMAP_INDEX(1, 2)] = KEY_END, // Red Button + [KEYMAP_INDEX(2, 0)] = KEY_BACK, // Back Button + [KEYMAP_INDEX(2, 1)] = KEY_HOME, // Home Button +}; + +static struct gpio_event_matrix_info htcleo_keypad_matrix_info = { + .info.func = gpio_event_matrix_func, + .keymap = htcleo_keymap, + .output_gpios = htcleo_col_gpios, + .input_gpios = htcleo_row_gpios, + .noutputs = ARRAY_SIZE(htcleo_col_gpios), + .ninputs = ARRAY_SIZE(htcleo_row_gpios), + .settle_time.tv.nsec = 40 * NSEC_PER_USEC, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .debounce_delay.tv.nsec = 5 * NSEC_PER_MSEC, + .flags = (GPIOKPF_LEVEL_TRIGGERED_IRQ | + GPIOKPF_REMOVE_PHANTOM_KEYS | + GPIOKPF_PRINT_UNMAPPED_KEYS), +}; + +static struct gpio_event_direct_entry htcleo_keypad_key_map[] = { + { + .gpio = HTCLEO_GPIO_POWER_KEY, + .code = KEY_END, // Power key + }, +}; + +static struct gpio_event_input_info htcleo_keypad_key_info = { + .info.func = gpio_event_input_func, + .info.no_suspend = true, + .flags = 0, + .type = EV_KEY, + .debounce_time.tv.nsec = 5 * NSEC_PER_MSEC, + .keymap = htcleo_keypad_key_map, + .keymap_size = ARRAY_SIZE(htcleo_keypad_key_map) +}; + +static struct gpio_event_info *htcleo_input_info[] = { + &htcleo_keypad_matrix_info.info, + &htcleo_keypad_key_info.info, +}; + +static struct gpio_event_platform_data htcleo_input_data = { + .names = { + "htcleo-keypad", + NULL, + }, + .info = htcleo_input_info, + .info_count = ARRAY_SIZE(htcleo_input_info), +}; + +static struct platform_device htcleo_input_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = 0, + .dev = { + .platform_data = &htcleo_input_data, + }, +}; + +/* +static int htcleo_reset_keys_up[] = { + KEY_VOLUMEUP, + 0, +}; + +static struct keyreset_platform_data htcleo_reset_keys_pdata = { + .keys_up = htcleo_reset_keys_up, + .keys_down = { + KEY_MENU, + 0 + }, +}; + +struct platform_device htcleo_reset_keys_device = { + .name = KEYRESET_NAME, + .dev = { + .platform_data = &htcleo_reset_keys_pdata + }, +}; +*/ + +static void keypad_led_brightness_set_work(struct work_struct *work) +{ + + unsigned long flags; + + enum led_brightness brightness; + uint8_t value; + + spin_lock_irqsave(&keypad_led_data.brightness_lock, flags); + brightness = keypad_led_data.brightness; + spin_unlock_irqrestore(&keypad_led_data.brightness_lock, flags); + + value = brightness >= 1 ? 1 : 0; + + /* avoid a flicker that can occur when writing the same value */ + if (keypad_led_data.oldval == value) + return; + keypad_led_data.oldval = value; + + gpio_set_value(HTCLEO_GPIO_KP_LED, value); + +} + +static void keypad_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + unsigned long flags; + + pr_debug("Setting %s brightness current %d new %d\n", + led_cdev->name, led_cdev->brightness, brightness); + + if (brightness > 255) + brightness = 255; + led_cdev->brightness = brightness; + + spin_lock_irqsave(&keypad_led_data.brightness_lock, flags); + keypad_led_data.brightness = brightness; + spin_unlock_irqrestore(&keypad_led_data.brightness_lock, flags); + + schedule_work(&keypad_led_data.brightness_work); +} + + +static int __init htcleo_init_keypad(void) +{ + int ret; + + if (!machine_is_htcleo()) + return 0; + + // ret = platform_device_register(&htcleo_reset_keys_device); + // if (ret != 0) + // return ret; + + ret = platform_device_register(&htcleo_input_device); + if (ret != 0) + return ret; + + ret = gpio_request(HTCLEO_GPIO_KP_LED, "keypad_led"); + if (ret < 0) { + pr_err("failed on request gpio keypad backlight on\n"); + goto exit; + } + ret = gpio_direction_output(HTCLEO_GPIO_KP_LED, 0); + if (ret < 0) { + pr_err("failed on gpio_direction_output keypad backlight on\n"); + goto err_gpio_kpl; + } + + keypad_led_data.ldev.name = "button-backlight"; + keypad_led_data.ldev.brightness_set = keypad_led_brightness_set; + keypad_led_data.oldval = 0; + mutex_init(&keypad_led_data.led_data_mutex); + INIT_WORK(&keypad_led_data.brightness_work, keypad_led_brightness_set_work); + spin_lock_init(&keypad_led_data.brightness_lock); + ret = led_classdev_register(&htcleo_input_device.dev, &keypad_led_data.ldev); + if (ret) { + keypad_led_data.ldev.name = NULL; + goto exit; + } + + return 0; +err_gpio_kpl: + gpio_free(HTCLEO_GPIO_KP_LED); +exit: + return ret; + +} + +device_initcall(htcleo_init_keypad);