diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 52ba325d0368..06ae24bda700 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -477,6 +477,11 @@ reg = <5>; remote-endpoint = <&lvds1_in_vp1>; }; + + odroid_sysfs { + compatible = "odroid-sysfs"; + status = "okay"; + }; }; &vp2 { diff --git a/arch/arm64/configs/odroidm1.config b/arch/arm64/configs/odroidm1.config index dfe6d2f6df8a..e08622f8a042 100644 --- a/arch/arm64/configs/odroidm1.config +++ b/arch/arm64/configs/odroidm1.config @@ -44,3 +44,4 @@ CONFIG_BT_HCIUART_INTEL=y CONFIG_BT_HCIBFUSB=y CONFIG_BT_HCIVHCI=y CONFIG_BT_MRVL=y +CONFIG_ODROID_SYSFS=y diff --git a/arch/arm64/configs/odroidm1s.config b/arch/arm64/configs/odroidm1s.config index dfe6d2f6df8a..e08622f8a042 100644 --- a/arch/arm64/configs/odroidm1s.config +++ b/arch/arm64/configs/odroidm1s.config @@ -44,3 +44,4 @@ CONFIG_BT_HCIUART_INTEL=y CONFIG_BT_HCIBFUSB=y CONFIG_BT_HCIVHCI=y CONFIG_BT_MRVL=y +CONFIG_ODROID_SYSFS=y diff --git a/drivers/Kconfig b/drivers/Kconfig index 06753118ab4a..58e45b168790 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -247,4 +247,5 @@ source "drivers/headset_observe/Kconfig" source "drivers/rknpu/Kconfig" +source "drivers/hardkernel/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 29874ab087a0..fdcbbfb72362 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -193,3 +193,4 @@ obj-$(CONFIG_RK_FLASH) += rkflash/ obj-$(CONFIG_RK_HEADSET) += headset_observe/ obj-$(CONFIG_RK_NAND) += rk_nand/ obj-$(CONFIG_ROCKCHIP_RKNPU) += rknpu/ +obj-$(CONFIG_ODROID_SYSFS) += hardkernel/ diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4e31f5227d39..6ba743713727 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -81,6 +81,23 @@ static struct wakeup_source deleted_ws = { static DEFINE_IDA(wakeup_ida); +/** + * wakeup_source_prepare - Prepare a new wakeup source for initialization. + * @ws: Wakeup source to prepare. + * @name: Pointer to the name of the new wakeup source. + * + * Callers must ensure that the @name string won't be freed when @ws is still in + * use. + */ +void wakeup_source_prepare(struct wakeup_source *ws, const char *name) +{ + if (ws) { + memset(ws, 0, sizeof(*ws)); + ws->name = name; + } +} +EXPORT_SYMBOL_GPL(wakeup_source_prepare); + /** * wakeup_source_create - Create a struct wakeup_source object. * @name: Name of the new wakeup source. diff --git a/drivers/hardkernel/Kconfig b/drivers/hardkernel/Kconfig new file mode 100644 index 000000000000..7988520d73c7 --- /dev/null +++ b/drivers/hardkernel/Kconfig @@ -0,0 +1,8 @@ +menu "ODROID Specific Hardware" + +config ODROID_SYSFS + bool "Hardkernel ODROID sysfs Support" + default y + help + Hardkernel sysfs +endmenu diff --git a/drivers/hardkernel/Makefile b/drivers/hardkernel/Makefile new file mode 100644 index 000000000000..7dab6ddfe61f --- /dev/null +++ b/drivers/hardkernel/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ODROID_SYSFS) += odroid-sysfs.o diff --git a/drivers/hardkernel/odroid-sysfs.c b/drivers/hardkernel/odroid-sysfs.c new file mode 100644 index 000000000000..40bc5d45fca6 --- /dev/null +++ b/drivers/hardkernel/odroid-sysfs.c @@ -0,0 +1,266 @@ +/* + * ODROID sysfs support for extra feature enhancement + * + * Copyright (C) 2014, Hardkernel Co,.Ltd + * Author: Charles Park + * Author: Dongjin Kim + * + * This driver has been modified to support ODROID-N1. + * Modified by Joy Cho + * + * 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. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * 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 + +bool touch_invert_x; +/*-------------------------------------------------------------------------*/ +static int __init touch_invert_x_para_setup(char *s) +{ + touch_invert_x = false; + if (!strncmp(s, "true", 4)) + touch_invert_x = true; + else if (!strncmp(s, "false", 5)) + touch_invert_x = false; + else { + pr_err("%s - wrong touch_invert_x parameter", __func__); + touch_invert_x = true; + } + + return 0; +} +__setup("touch_invert_x=", touch_invert_x_para_setup); + +bool get_touch_invert_x(void) +{ + return touch_invert_x; +} +EXPORT_SYMBOL(get_touch_invert_x); + +bool touch_invert_y; +/*-------------------------------------------------------------------------*/ +static int __init touch_invert_y_para_setup(char *s) +{ + touch_invert_y = false; + if (!strncmp(s, "true", 4)) + touch_invert_y = true; + else if (!strncmp(s, "false", 5)) + touch_invert_y = false; + else { + pr_err("%s - wrong touch_invert_y parameter", __func__); + touch_invert_y = true; + } + + return 0; +} +__setup("touch_invert_y=", touch_invert_y_para_setup); + +bool get_touch_invert_y(void) +{ + return touch_invert_y; +} +EXPORT_SYMBOL(get_touch_invert_y); + +bool get_disable_vu7(void) +{ + return touch_invert_y; +} +EXPORT_SYMBOL(get_disable_vu7); + +static int prevent_sleep = 0; + +static int __init prevent_sleep_setup(char *s) +{ + if (!strcmp(s, "true") || !strcmp(s, "1")) + prevent_sleep = 1; + else + prevent_sleep = 0; + + return 0; +} +__setup("prevent_sleep=", prevent_sleep_setup); + +struct wakeup_source wake_src; + +MODULE_AUTHOR("Hardkernel Co,.Ltd"); +MODULE_DESCRIPTION("SYSFS driver for ODROID hardware"); +MODULE_LICENSE("GPL"); + +static struct hrtimer input_timer; +static struct input_dev *input_dev; +static int keycode[] = { KEY_POWER, }; +static int key_release_seconds; + +static enum hrtimer_restart input_timer_function(struct hrtimer *timer) +{ + key_release_seconds = 0; + input_report_key(input_dev, KEY_POWER, 0); + input_sync(input_dev); + + return HRTIMER_NORESTART; +} + +static int init_input_dev(void) +{ + int error = 0; + +/*********************************************************************** + * virtual key init (Power Off Key) + ***********************************************************************/ + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "vt-input"; + input_dev->phys = "vt-input/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x16B4; + input_dev->id.product = 0x0701; + input_dev->id.version = 0x0001; + input_dev->keycode = keycode; + input_dev->keycodesize = sizeof(keycode[0]); + input_dev->keycodemax = ARRAY_SIZE(keycode); + + set_bit(EV_KEY, input_dev->evbit); + set_bit(KEY_POWER & KEY_MAX, input_dev->keybit); + + error = input_register_device(input_dev); + if (error) { + input_free_device(input_dev); + return error; + } + + pr_info("%s input driver registered!!\n", "Virtual-Key"); + + hrtimer_init(&input_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + input_timer.function = input_timer_function; + + return error; +} + +static ssize_t odroid_sysfs_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + return 0; +} + +static CLASS_ATTR_RO(odroid_sysfs); + +static struct attribute *odroid_sysfs_class_attrs[] = { + &class_attr_odroid_sysfs.attr, + NULL, +}; +ATTRIBUTE_GROUPS(odroid_sysfs_class); + +static struct class odroid_sysfs_class = { + .name = "odroid", + .owner = THIS_MODULE, + .class_groups = odroid_sysfs_class_groups, +}; + +static int odroid_sysfs_probe(struct platform_device *pdev) +{ + int error = 0; + if (prevent_sleep) { + __pm_stay_awake(&wake_src); + } + +#ifdef CONFIG_USE_OF + struct device_node *node; + + if (pdev->dev.of_node) + node = pdev->dev.of_node; +#endif + + if (input_dev == NULL) + error = init_input_dev(); + + return error; +} + +static int odroid_sysfs_remove(struct platform_device *pdev) +{ + if (prevent_sleep) + __pm_relax(&wake_src); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int odroid_sysfs_suspend(struct platform_device *dev, pm_message_t state) +{ + pr_info("%s\n", __func__); + + return 0; +} + +static int odroid_sysfs_resume(struct platform_device *dev) +{ + pr_info("%s\n", __func__); + + return 0; +} +#endif + +static const struct of_device_id odroid_sysfs_dt[] = { + { .compatible = "odroid-sysfs", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, odroid_sysfs_dt); + +static struct platform_driver odroid_sysfs_driver = { + .driver = { + .name = "odroid-sysfs", + .owner = THIS_MODULE, + .of_match_table = odroid_sysfs_dt, + }, + .probe = odroid_sysfs_probe, + .remove = odroid_sysfs_remove, +#ifdef CONFIG_PM_SLEEP + .suspend = odroid_sysfs_suspend, + .resume = odroid_sysfs_resume, +#endif +}; + +static int __init odroid_sysfs_init(void) +{ + int error = class_register(&odroid_sysfs_class); + + if (prevent_sleep) { + wakeup_source_init(&wake_src, "odroid_sysfs"); + } + + if (error < 0) + return error; + + return platform_driver_register(&odroid_sysfs_driver); +} + +static void __exit odroid_sysfs_exit(void) +{ + platform_driver_unregister(&odroid_sysfs_driver); + class_unregister(&odroid_sysfs_class); +} + +module_init(odroid_sysfs_init); +module_exit(odroid_sysfs_exit); diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index 77f4849e3418..8e028b635f68 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -95,6 +95,7 @@ static inline void device_set_wakeup_path(struct device *dev) } /* drivers/base/power/wakeup.c */ +extern void wakeup_source_prepare(struct wakeup_source *ws, const char *name); extern struct wakeup_source *wakeup_source_create(const char *name); extern void wakeup_source_destroy(struct wakeup_source *ws); extern void wakeup_source_add(struct wakeup_source *ws); @@ -129,6 +130,9 @@ static inline bool device_can_wakeup(struct device *dev) return dev->power.can_wakeup; } +static inline void wakeup_source_prepare(struct wakeup_source *ws, + const char *name) {} + static inline struct wakeup_source *wakeup_source_create(const char *name) { return NULL; @@ -232,4 +236,11 @@ static inline int device_init_wakeup(struct device *dev, bool enable) } } +static inline void wakeup_source_init(struct wakeup_source *ws, + const char *name) +{ + wakeup_source_prepare(ws, name); + wakeup_source_add(ws); +} + #endif /* _LINUX_PM_WAKEUP_H */