From 7646d275b54ce273d84be0c7e313858fc30f3eb8 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Fri, 31 Mar 2017 21:08:16 +0800 Subject: [PATCH] led: add system gpio led driver support PD#138714: led: add system gpio led driver support add new configuration: +CONFIG_AMLOGIC_LED=y +CONFIG_AMLOGIC_LED_SYS=y Change-Id: I34c3740eaf9efb02667d9e3d7e95ef8570e2c63c Signed-off-by: Bo Yang --- MAINTAINERS | 4 + arch/arm64/configs/meson64_defconfig | 2 + drivers/amlogic/Kconfig | 2 + drivers/amlogic/Makefile | 2 + drivers/amlogic/led/Kconfig | 28 ++++ drivers/amlogic/led/Makefile | 5 + drivers/amlogic/led/led_sys.c | 233 +++++++++++++++++++++++++++ drivers/amlogic/led/led_sys.h | 47 ++++++ 8 files changed, 323 insertions(+) create mode 100644 drivers/amlogic/led/Kconfig create mode 100644 drivers/amlogic/led/Makefile create mode 100644 drivers/amlogic/led/led_sys.c create mode 100644 drivers/amlogic/led/led_sys.h diff --git a/MAINTAINERS b/MAINTAINERS index 0e995849cdb9..8d0a7dcaff38 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13739,6 +13739,10 @@ AMLOGIC WATCHDOG DRIVER SUPPORT M: Bo Yang F: drivers/amlogic/watchdog/* +AMLOGIC LED DRIVER SUPPORT +M: Bo Yang +F: drivers/amlogic/led/* + AMLOGIC JTAG DRIVER SUPPORT M: Bo Yang F: drivers/amlogic/jtag/* diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index e54033ee70d2..788981c704ec 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -238,6 +238,8 @@ CONFIG_AMLOGIC_GPU_THERMAL=y CONFIG_AMLOGIC_GPUCORE_THERMAL=y CONFIG_AMLOGIC_AUDIO_DSP=y CONFIG_AMLOGIC_GX_SUSPEND=y +CONFIG_AMLOGIC_LED=y +CONFIG_AMLOGIC_LED_SYS=y CONFIG_AMLOGIC_JTAG=y CONFIG_AMLOGIC_JTAG_MESON=y CONFIG_AMLOGIC_WDT=y diff --git a/drivers/amlogic/Kconfig b/drivers/amlogic/Kconfig index 9a0f3b502913..305a4d335231 100644 --- a/drivers/amlogic/Kconfig +++ b/drivers/amlogic/Kconfig @@ -73,6 +73,8 @@ source "drivers/amlogic/audiodsp/Kconfig" source "drivers/amlogic/pm/Kconfig" +source "drivers/amlogic/led/Kconfig" + source "drivers/amlogic/jtag/Kconfig" source "drivers/amlogic/watchdog/Kconfig" diff --git a/drivers/amlogic/Makefile b/drivers/amlogic/Makefile index 8d0849de17fd..6a8af9686263 100644 --- a/drivers/amlogic/Makefile +++ b/drivers/amlogic/Makefile @@ -69,6 +69,8 @@ obj-$(CONFIG_AMLOGIC_AUDIO_DSP) += audiodsp/ obj-$(CONFIG_AMLOGIC_GX_SUSPEND) += pm/ +obj-$(CONFIG_AMLOGIC_LED) += led/ + obj-$(CONFIG_AMLOGIC_JTAG) += jtag/ obj-$(CONFIG_AMLOGIC_WDT) += watchdog/ diff --git a/drivers/amlogic/led/Kconfig b/drivers/amlogic/led/Kconfig new file mode 100644 index 000000000000..8253136876da --- /dev/null +++ b/drivers/amlogic/led/Kconfig @@ -0,0 +1,28 @@ +# +# LED drivers configuration +# + +menuconfig AMLOGIC_LED + bool "Amlogic LED Support" + default n + help + Say Y here to get to see options for led drivers. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be + skipped and disabled. + + +if AMLOGIC_LED + +config AMLOGIC_LED_SYS + bool "System LED Support" + depends on LEDS_CLASS + default n + help + This option enables support for system led drivers. + + Enable this option to allow the userspace to control + the system led. + +endif diff --git a/drivers/amlogic/led/Makefile b/drivers/amlogic/led/Makefile new file mode 100644 index 000000000000..ea6e3a77a626 --- /dev/null +++ b/drivers/amlogic/led/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for LED +# + +obj-$(CONFIG_AMLOGIC_LED_SYS) += led_sys.o diff --git a/drivers/amlogic/led/led_sys.c b/drivers/amlogic/led/led_sys.c new file mode 100644 index 000000000000..24b9e63d5476 --- /dev/null +++ b/drivers/amlogic/led/led_sys.c @@ -0,0 +1,233 @@ +/* + * drivers/amlogic/led/led_sys.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * 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. + * + */ + +#define pr_fmt(fmt) "sysled: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "led_sys.h" + + +#define AML_DEV_NAME "sysled" +#define AML_LED_NAME "led-sys" + + +static void aml_sysled_output_setup(struct aml_sysled_dev *ldev, + enum led_brightness value) +{ + unsigned int level = !!value; + + if (ldev->d.active_low) + level = !level; + gpio_direction_output(ldev->d.pin, level); +} + +static void aml_sysled_work(struct work_struct *work) +{ + struct aml_sysled_dev *ldev; + + ldev = container_of(work, struct aml_sysled_dev, work); + + mutex_lock(&ldev->lock); + aml_sysled_output_setup(ldev, ldev->new_brightness); + mutex_unlock(&ldev->lock); +} + + +static void aml_sysled_brightness_set(struct led_classdev *cdev, + enum led_brightness value) +{ + struct aml_sysled_dev *ldev; + struct platform_device *pdev; + + pdev = to_platform_device(cdev->dev->parent); + ldev = platform_get_drvdata(pdev); + ldev->new_brightness = value; + schedule_work(&ldev->work); +} + + +static int aml_sysled_dt_parse(struct platform_device *pdev) +{ + struct device_node *node; + struct aml_sysled_dev *ldev; + int led_gpio; + enum of_gpio_flags flags; + + ldev = platform_get_drvdata(pdev); + node = pdev->dev.of_node; + if (!node) { + pr_err("failed to find node for %s\n", AML_DEV_NAME); + return -ENODEV; + } + + led_gpio = of_get_named_gpio_flags(node, "led_gpio", 0, &flags); + if (!gpio_is_valid(led_gpio)) { + pr_err("gpio %d is not valid\n", led_gpio); + return -EINVAL; + } + + ldev->d.pin = led_gpio; + ldev->d.active_low = flags & OF_GPIO_ACTIVE_LOW; + pr_info("led_gpio = %u\n", ldev->d.pin); + pr_info("active_low = %u\n", ldev->d.active_low); + gpio_request(ldev->d.pin, AML_DEV_NAME); + gpio_direction_output(ldev->d.pin, 1); + + return 0; +} + + + +static const struct of_device_id aml_sysled_dt_match[] = { + { + .compatible = "amlogic, sysled", + }, + {}, +}; + + +static int aml_sysled_probe(struct platform_device *pdev) +{ + struct aml_sysled_dev *ldev; + int ret; + + ldev = kzalloc(sizeof(struct aml_sysled_dev), GFP_KERNEL); + + /* set driver data */ + platform_set_drvdata(pdev, ldev); + + /* parse dt param */ + ret = aml_sysled_dt_parse(pdev); + if (ret) + return ret; + + /* register led class device */ + ldev->cdev.name = AML_LED_NAME; + ldev->cdev.brightness_set = aml_sysled_brightness_set; + mutex_init(&ldev->lock); + INIT_WORK(&ldev->work, aml_sysled_work); + ret = led_classdev_register(&pdev->dev, &ldev->cdev); + if (ret < 0) { + kfree(ldev); + return ret; + } + + /* set led default on */ + aml_sysled_output_setup(ldev, 1); + + pr_info("module probed ok\n"); + return 0; +} + + +static int __exit aml_sysled_remove(struct platform_device *pdev) +{ + struct aml_sysled_dev *ldev = platform_get_drvdata(pdev); + + led_classdev_unregister(&ldev->cdev); + cancel_work_sync(&ldev->work); + gpio_free(ldev->d.pin); + platform_set_drvdata(pdev, NULL); + kfree(ldev); + pr_info("module removed ok\n"); + return 0; +} + + +static void aml_sysled_shutdown(struct platform_device *pdev) +{ + struct aml_sysled_dev *ldev = platform_get_drvdata(pdev); + /* set led off*/ + aml_sysled_output_setup(ldev, 0); + pr_info("module shutdown ok\n"); +} + + +#ifdef CONFIG_PM +static int aml_sysled_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct aml_sysled_dev *ldev = platform_get_drvdata(pdev); + /* set led off */ + aml_sysled_output_setup(ldev, 0); + pr_info("module suspend ok\n"); + return 0; +} + +static int aml_sysled_resume(struct platform_device *pdev) +{ + struct aml_sysled_dev *ldev = platform_get_drvdata(pdev); + /* set led on */ + aml_sysled_output_setup(ldev, 1); + pr_info("module resume ok\n"); + return 0; +} +#endif + + +static struct platform_driver aml_sysled_driver = { + .driver = { + .name = AML_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = aml_sysled_dt_match, + }, + .probe = aml_sysled_probe, + .remove = __exit_p(aml_sysled_remove), + .shutdown = aml_sysled_shutdown, +#ifdef CONFIG_PM + .suspend = aml_sysled_suspend, + .resume = aml_sysled_resume, +#endif +}; + + +static int __init aml_sysled_init(void) +{ + pr_info("module init\n"); + if (platform_driver_register(&aml_sysled_driver)) { + pr_err("failed to register driver\n"); + return -ENODEV; + } + + return 0; +} + + +static void __exit aml_sysled_exit(void) +{ + pr_info("module exit\n"); + platform_driver_unregister(&aml_sysled_driver); +} + + +module_init(aml_sysled_init); +module_exit(aml_sysled_exit); + +MODULE_DESCRIPTION("Amlogic sys led driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Amlogic, Inc."); + diff --git a/drivers/amlogic/led/led_sys.h b/drivers/amlogic/led/led_sys.h new file mode 100644 index 000000000000..c07f0fe0e4a4 --- /dev/null +++ b/drivers/amlogic/led/led_sys.h @@ -0,0 +1,47 @@ +/* + * drivers/amlogic/led/led_sys.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef __AML_LED_SYS_H +#define __AML_LED_SYS_H + +#include +#include +#include + +enum { + LED_GPIO_STATE_OFF = 0, + LED_GPIO_STATE_ON, +}; + +struct aml_led_gpio { + const char *name; + unsigned int pin; + unsigned int active_low; + unsigned int state; +}; + + +struct aml_sysled_dev { + struct aml_led_gpio d; + struct led_classdev cdev; + enum led_brightness new_brightness; + + struct work_struct work; + struct mutex lock; +}; + +#endif -- 2.20.1