diff --git a/kernel/linux-imx6_3.14.28/arch/arm/boot/dts/imx6s-prime-oven.dts b/kernel/linux-imx6_3.14.28/arch/arm/boot/dts/imx6s-prime-oven.dts index c4658f1..f0be4bc 100755 --- a/kernel/linux-imx6_3.14.28/arch/arm/boot/dts/imx6s-prime-oven.dts +++ b/kernel/linux-imx6_3.14.28/arch/arm/boot/dts/imx6s-prime-oven.dts @@ -21,24 +21,14 @@ model = "Freescale i.MX6 Solo/DualLite Prime Oven Device Board(PFUZE100)"; compatible = "fsl,imx6dl-prime-oven", "fsl,imx6dl"; - rotary@0 { - compatible = "rotary-encoder"; - gpios = <&gpio6 11 1>, <&gpio6 10 1>; - linux,axis = <1>; /* ABS_Y */ - rotary-encoder,steps = <24>; - rotary-encoder,rollover; - }; - - gpio_keys { - compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; - autorepeat; - button@21 { - label = "GPIO Key UP"; - linux,code = ; - gpios = <&gpio6 14 1>; - }; + prime_encoder@0 { + compatible = "prime-encoder"; + gpios = <&gpio6 11 1>, <&gpio6 10 1>, <&gpio6 14 1>; + /* add larche@falinux.com - private value */ + prime-encoder,button; + prime-encoder,left_code = ; + prime-encoder,right_code = ; + prime-encoder,center_code = ; }; }; diff --git a/kernel/linux-imx6_3.14.28/arch/arm/configs/imx6s_prime_oven_defconfig b/kernel/linux-imx6_3.14.28/arch/arm/configs/imx6s_prime_oven_defconfig index 2e38cc7..8781b31 100644 --- a/kernel/linux-imx6_3.14.28/arch/arm/configs/imx6s_prime_oven_defconfig +++ b/kernel/linux-imx6_3.14.28/arch/arm/configs/imx6s_prime_oven_defconfig @@ -1388,7 +1388,8 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_CM109 is not set # CONFIG_INPUT_UINPUT is not set # CONFIG_INPUT_PCF8574 is not set -CONFIG_INPUT_GPIO_ROTARY_ENCODER=y +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +CONFIG_INPUT_GPIO_PRIME_ENCODER=y # CONFIG_INPUT_ADXL34X is not set # CONFIG_INPUT_IMS_PCU is not set # CONFIG_INPUT_CMA3000 is not set diff --git a/kernel/linux-imx6_3.14.28/drivers/input/misc/Kconfig b/kernel/linux-imx6_3.14.28/drivers/input/misc/Kconfig index 5050ba5..4d5e1df 100644 --- a/kernel/linux-imx6_3.14.28/drivers/input/misc/Kconfig +++ b/kernel/linux-imx6_3.14.28/drivers/input/misc/Kconfig @@ -490,6 +490,17 @@ config INPUT_GPIO_ROTARY_ENCODER To compile this driver as a module, choose M here: the module will be called rotary_encoder. +config INPUT_GPIO_PRIME_ENCODER + tristate "Prime encoders connected to GPIO pins" + depends on GPIOLIB + help + Say Y here to add support for rotary encoders connected to GPIO lines. + Check file:Documentation/input/rotary-encoder.txt for more + information. + + To compile this driver as a module, choose M here: the + module will be called rotary_encoder. + config INPUT_RB532_BUTTON tristate "Mikrotik Routerboard 532 button interface" depends on MIKROTIK_RB532 diff --git a/kernel/linux-imx6_3.14.28/drivers/input/misc/Makefile b/kernel/linux-imx6_3.14.28/drivers/input/misc/Makefile index 0368dec..3fffcd9 100644 --- a/kernel/linux-imx6_3.14.28/drivers/input/misc/Makefile +++ b/kernel/linux-imx6_3.14.28/drivers/input/misc/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o +obj-$(CONFIG_INPUT_GPIO_PRIME_ENCODER) += prime_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o diff --git a/kernel/linux-imx6_3.14.28/drivers/input/misc/prime_encoder.c b/kernel/linux-imx6_3.14.28/drivers/input/misc/prime_encoder.c new file mode 100644 index 0000000..a56b9ff --- /dev/null +++ b/kernel/linux-imx6_3.14.28/drivers/input/misc/prime_encoder.c @@ -0,0 +1,378 @@ +/* + * rotary_encoder.c + * + * (c) 2009 Daniel Mack + * Copyright (C) 2011 Johan Hovold + * + * state machine code inspired by code from Tim Ruetz + * + * A generic driver for rotary encoders connected to GPIO lines. + * See file:Documentation/input/rotary-encoder.txt for more information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "prime-encoder" + +struct rotary_encoder { + struct input_dev *input; + const struct rotary_encoder_platform_data *pdata; + + unsigned int irq_a; + unsigned int irq_b; + // add larche@falinux.com, for button + unsigned int irq_button; + char last_value; + unsigned int l_key_state; + unsigned int r_key_state; +}; + +/*** + * add larche@falinux.com + * + * ab + * + * 11 + *{R} 10 01 {L} + * 00 + */ +static int rotary_encoder_get_value(const struct rotary_encoder_platform_data *pdata) +{ + int a = !!gpio_get_value(pdata->gpio_a); + int b = !!gpio_get_value(pdata->gpio_b); + int val = 0; + + val&=0x0; + val|=(a<<1); + val|=(b<<0); + + return val; +} + +static irqreturn_t rotary_encoder_irq_center_button(int irq, void *dev_id) +{ + struct rotary_encoder *encoder = dev_id; + const struct rotary_encoder_platform_data *pdata = encoder->pdata; + int key_state; + + key_state = gpio_get_value(pdata->gpio_button) ^ pdata->inverted_button; + input_event(encoder->input, EV_KEY, pdata->center_code, !!key_state); + input_sync(encoder->input); + + return IRQ_HANDLED; +} + +static irqreturn_t rotary_encoder_irq_single_step(int irq, void *dev_id) +{ + struct rotary_encoder *encoder = dev_id; + const struct rotary_encoder_platform_data *pdata = encoder->pdata; + int state = 0; + int key_state = 0; + + state = rotary_encoder_get_value(pdata); + + switch(encoder->last_value) + { + case 0x0: + if(state == 0x2) + { + key_state = (encoder->r_key_state ? 0 : 1); + encoder->r_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->right_code, !!key_state); + } + else if(state == 0x1) + { + key_state = (encoder->l_key_state ? 0 : 1); + encoder->l_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->left_code, !!key_state); + } + + break; + + case 0x1: + if(state == 0x0) + { + key_state = (encoder->r_key_state ? 0 : 1); + encoder->r_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->right_code, !!key_state); + } + else if(state == 0x3) + { + key_state = (encoder->l_key_state ? 0 : 1); + encoder->l_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->left_code, !!key_state); + } + + break; + + case 0x2: + if(state == 0x3) + { + key_state = (encoder->r_key_state ? 0 : 1); + encoder->r_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->right_code, !!key_state); + } + else if(state == 0x0) + { + key_state = (encoder->l_key_state ? 0 : 1); + encoder->l_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->left_code, !!key_state); + } + + break; + + case 0x3: + if(state == 0x1) + { + key_state = (encoder->r_key_state ? 0 : 1); + encoder->r_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->right_code, !!key_state); + } + else if(state == 0x2) + { + key_state = (encoder->l_key_state ? 0 : 1); + encoder->l_key_state = key_state; + input_event(encoder->input, EV_KEY, pdata->left_code, !!key_state); + } + + break; + } + + input_sync(encoder->input); + + encoder->last_value = state; + + return IRQ_HANDLED; +} + +#ifdef CONFIG_OF +static struct of_device_id rotary_encoder_of_match[] = { + { .compatible = "prime-encoder", }, + { }, +}; +MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); + +static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev) +{ + const struct of_device_id *of_id = + of_match_device(rotary_encoder_of_match, dev); + struct device_node *np = dev->of_node; + struct rotary_encoder_platform_data *pdata; + enum of_gpio_flags flags; + + if (!of_id || !np) + return NULL; + + pdata = kzalloc(sizeof(struct rotary_encoder_platform_data), + GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->gpio_a = of_get_gpio_flags(np, 0, &flags); + pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW; + + pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); + pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; + + // add larche@falinux.com + pdata->is_button = !!of_get_property(np, + "prime-encoder,button", NULL); + if(pdata->is_button) { + pdata->gpio_button = of_get_gpio_flags(np, 2, &flags); + pdata->inverted_button = flags & OF_GPIO_ACTIVE_LOW; + if( of_property_read_u32( np, "prime-encoder,left_code", &pdata->left_code) ) + pdata->left_code = KEY_F1; + if( of_property_read_u32( np, "prime-encoder,right_code", &pdata->right_code) ) + pdata->right_code = KEY_F2; + if( of_property_read_u32( np, "prime-encoder,center_code", &pdata->center_code) ) + pdata->center_code = KEY_F3; + } + + return pdata; +} +#else +static inline struct rotary_encoder_platform_data * +rotary_encoder_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + +static int rotary_encoder_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev); + struct rotary_encoder *encoder; + struct input_dev *input; + irq_handler_t handler; + irq_handler_t handler_button; + int err; + + if (!pdata) { + pdata = rotary_encoder_parse_dt(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + + if (!pdata) { + dev_err(dev, "missing platform data\n"); + return -EINVAL; + } + } + + encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); + input = input_allocate_device(); + if (!encoder || !input) { + err = -ENOMEM; + goto exit_free_mem; + } + + encoder->input = input; + encoder->pdata = pdata; + + input->name = pdev->name; + input->id.bustype = BUS_HOST; + input->dev.parent = dev; + + /* request the GPIOs */ + err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); + if (err) { + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); + goto exit_free_mem; + } + + err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); + if (err) { + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); + goto exit_free_gpio_a; + } + + if(pdata->is_button) { + err = gpio_request_one(pdata->gpio_button, GPIOF_IN, dev_name(dev)); + if (err) { + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_button); + goto exit_free_gpio_b; + } + } + + encoder->irq_a = gpio_to_irq(pdata->gpio_a); + encoder->irq_b = gpio_to_irq(pdata->gpio_b); + encoder->irq_button = gpio_to_irq(pdata->gpio_button); + + handler = &rotary_encoder_irq_single_step; + handler_button = &rotary_encoder_irq_center_button; + encoder->last_value = rotary_encoder_get_value(pdata); + + err = request_irq(encoder->irq_a, handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRV_NAME, encoder); + if (err) { + dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); + goto exit_free_gpio_button; + } + + err = request_irq(encoder->irq_b, handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRV_NAME, encoder); + if (err) { + dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); + goto exit_free_irq_a; + } + + err = request_irq(encoder->irq_button, handler_button, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + DRV_NAME, encoder); + if (err) { + dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); + goto exit_free_irq_b; + } + + err = input_register_device(input); + if (err) { + dev_err(dev, "failed to register input device\n"); + goto exit_free_irq_button; + } + + input_set_capability(input, EV_KEY, pdata->left_code); // Left + input_set_capability(input, EV_KEY, pdata->right_code); // Right + input_set_capability(input, EV_KEY, pdata->center_code); // Center + + encoder->l_key_state = 0; + encoder->r_key_state = 0; + + platform_set_drvdata(pdev, encoder); + + return 0; + +exit_free_irq_button: + free_irq(encoder->irq_button, encoder); +exit_free_irq_b: + free_irq(encoder->irq_b, encoder); +exit_free_irq_a: + free_irq(encoder->irq_a, encoder); +exit_free_gpio_button: + if(pdata->is_button) { + gpio_free(pdata->gpio_button); + } +exit_free_gpio_b: + gpio_free(pdata->gpio_b); +exit_free_gpio_a: + gpio_free(pdata->gpio_a); +exit_free_mem: + input_free_device(input); + kfree(encoder); + if (!dev_get_platdata(&pdev->dev)) + kfree(pdata); + + return err; + +} + +static int rotary_encoder_remove(struct platform_device *pdev) +{ + struct rotary_encoder *encoder = platform_get_drvdata(pdev); + const struct rotary_encoder_platform_data *pdata = encoder->pdata; + + free_irq(encoder->irq_a, encoder); + free_irq(encoder->irq_b, encoder); + gpio_free(pdata->gpio_a); + gpio_free(pdata->gpio_b); + + input_unregister_device(encoder->input); + kfree(encoder); + + if (!dev_get_platdata(&pdev->dev)) + kfree(pdata); + + return 0; +} + +static struct platform_driver rotary_encoder_driver = { + .probe = rotary_encoder_probe, + .remove = rotary_encoder_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rotary_encoder_of_match), + } +}; +module_platform_driver(rotary_encoder_driver); + +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DESCRIPTION("GPIO rotary encoder driver"); +MODULE_AUTHOR("Daniel Mack , Johan Hovold"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/linux-imx6_3.14.28/include/linux/prime_encoder.h b/kernel/linux-imx6_3.14.28/include/linux/prime_encoder.h new file mode 100644 index 0000000..38b00d5 --- /dev/null +++ b/kernel/linux-imx6_3.14.28/include/linux/prime_encoder.h @@ -0,0 +1,17 @@ +#ifndef __ROTARY_ENCODER_H__ +#define __ROTARY_ENCODER_H__ + +struct rotary_encoder_platform_data { + unsigned int gpio_a; + unsigned int gpio_b; + unsigned int gpio_button; + unsigned int inverted_a; + unsigned int inverted_b; + unsigned int inverted_button; + unsigned int left_code; + unsigned int right_code; + unsigned int center_code; + bool is_button; +}; + +#endif /* __ROTARY_ENCODER_H__ */