/* 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);