Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757045AbYGOPT1 (ORCPT ); Tue, 15 Jul 2008 11:19:27 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752380AbYGOPTU (ORCPT ); Tue, 15 Jul 2008 11:19:20 -0400 Received: from rtsoft3.corbina.net ([85.21.88.6]:5673 "EHLO buildserver.ru.mvista.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1751661AbYGOPTT (ORCPT ); Tue, 15 Jul 2008 11:19:19 -0400 Date: Tue, 15 Jul 2008 19:19:17 +0400 From: Anton Vorontsov To: Richard Purdie Cc: Stephen Rothwell , Kumar Gala , linux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org Subject: [PATCH v3] leds: implement OpenFirmare GPIO LED driver Message-ID: <20080715151917.GA30607@polina.dev.rtsoft.ru> References: <1216133032.5345.73.camel@dax.rpnet.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Disposition: inline In-Reply-To: <1216133032.5345.73.camel@dax.rpnet.com> User-Agent: Mutt/1.5.18 (2008-05-17) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7158 Lines: 255 Despite leds-gpio and leds-openfirmware-gpio similar purposes, there is not much code can be shared between the two drivers (both are mostly driver bindings anyway). Signed-off-by: Anton Vorontsov --- - dropped Documentation/powerpc/ changes, since Kumar applied them via powerpc tree. - renamed leds-of-gpio to leds-openfirmware-gpio drivers/leds/Kconfig | 8 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-openfirmware-gpio.c | 194 +++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 0 deletions(-) create mode 100644 drivers/leds/leds-openfirmware-gpio.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 1c35dfa..a645e8d 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -119,6 +119,14 @@ config LEDS_GPIO outputs. To be useful the particular board must have LEDs and they must be connected to the GPIO lines. +config LEDS_OPENFIRMWARE_GPIO + tristate "OpenFirmware bindings for GPIO connected LEDs" + depends on LEDS_CLASS && OF_GPIO + help + This option enables support for the LEDs connected to GPIO + outputs. To be useful the particular board must have LEDs + and they must be connected to the GPIO lines. + config LEDS_CM_X270 tristate "LED Support for the CM-X270 LEDs" depends on LEDS_CLASS && MACH_ARMCORE diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7156f99..0258ab7 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o +obj-$(CONFIG_LEDS_OPENFIRMWARE_GPIO) += leds-openfirmware-gpio.o obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o diff --git a/drivers/leds/leds-openfirmware-gpio.c b/drivers/leds/leds-openfirmware-gpio.c new file mode 100644 index 0000000..ce2c3cd --- /dev/null +++ b/drivers/leds/leds-openfirmware-gpio.c @@ -0,0 +1,194 @@ +/* + * OpenFirmware bindings for GPIO connected LEDs + * + * Copyright (C) 2007 8D Technologies inc. + * Raphael Assenat + * Copyright (C) 2008 MontaVista Software, Inc. + * Anton Vorontsov + * + * 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 + +struct of_gpio_led { + struct device_node *np; + struct led_classdev cdev; + unsigned int gpio; + struct work_struct work; + u8 new_level; + u8 can_sleep; +}; + +static void gpio_led_work(struct work_struct *work) +{ + struct of_gpio_led *led = container_of(work, struct of_gpio_led, work); + + gpio_set_value_cansleep(led->gpio, led->new_level); +} + +static void gpio_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct of_gpio_led *led = container_of(led_cdev, struct of_gpio_led, + cdev); + int level; + + if (value == LED_OFF) + level = 0; + else + level = 1; + + /* Setting GPIOs with I2C/etc requires a task context, and we don't + * seem to have a reliable way to know if we're already in one; so + * let's just assume the worst. + */ + if (led->can_sleep) { + led->new_level = level; + schedule_work(&led->work); + } else { + gpio_set_value(led->gpio, level); + } +} + +static int __devinit of_gpio_leds_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + int ret; + struct of_gpio_led *led; + struct device_node *np = ofdev->node; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->np = of_node_get(np); + + ret = of_get_gpio(np, 0); + if (!gpio_is_valid(ret)) { + dev_err(&ofdev->dev, "gpio is invalid\n"); + goto err_get_gpio; + } + led->gpio = ret; + led->can_sleep = gpio_cansleep(led->gpio); + + led->cdev.name = of_get_property(np, "label", NULL); + if (!led->cdev.name) + led->cdev.name = dev_name(&ofdev->dev); + led->cdev.brightness_set = gpio_led_set; + + ret = gpio_request(led->gpio, dev_name(&ofdev->dev)); + if (ret < 0) { + dev_err(&ofdev->dev, "could not request gpio, status is %d\n", + ret); + goto err_gpio; + } + + ret = gpio_direction_output(led->gpio, 0); + if (ret) { + dev_err(&ofdev->dev, "gpio could not be an output, " + "status is %d\n", ret); + goto err_gpio; + } + + INIT_WORK(&led->work, gpio_led_work); + dev_set_drvdata(&ofdev->dev, led); + + ret = led_classdev_register(&ofdev->dev, &led->cdev); + if (ret < 0) { + dev_err(&ofdev->dev, "could register led cdev, status is %d\n", + ret); + gpio_free(led->gpio); + goto err_reg_cdev; + } + + return 0; + +err_reg_cdev: + cancel_work_sync(&led->work); +err_gpio: + gpio_free(led->gpio); +err_get_gpio: + of_node_put(led->np); + kfree(led); + return ret; +} + +static int __devexit of_gpio_leds_remove(struct of_device *ofdev) +{ + struct of_gpio_led *led = dev_get_drvdata(&ofdev->dev); + + led_classdev_unregister(&led->cdev); + cancel_work_sync(&led->work); + gpio_free(led->gpio); + of_node_put(led->np); + kfree(led); + + return 0; +} + +#ifdef CONFIG_PM +static int of_gpio_led_suspend(struct of_device *ofdev, pm_message_t state) +{ + struct of_gpio_led *led = dev_get_drvdata(&ofdev->dev); + + led_classdev_suspend(&led->cdev); + return 0; +} + +static int of_gpio_led_resume(struct of_device *ofdev) +{ + struct of_gpio_led *led = dev_get_drvdata(&ofdev->dev); + + led_classdev_resume(&led->cdev); + return 0; +} +#else +#define of_gpio_led_suspend NULL +#define of_gpio_led_resume NULL +#endif /* CONFIG_PM */ + +static const struct of_device_id of_gpio_leds_match[] = { + { .compatible = "gpio-led", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_gpio_leds_match); + +static struct of_platform_driver of_gpio_leds_driver = { + .driver = { + .name = "of_gpio_leds", + .owner = THIS_MODULE, + }, + .match_table = of_gpio_leds_match, + .probe = of_gpio_leds_probe, + .remove = __devexit_p(of_gpio_leds_remove), + .suspend = of_gpio_led_suspend, + .resume = of_gpio_led_resume, +}; + +static int __init of_gpio_leds_init(void) +{ + return of_register_platform_driver(&of_gpio_leds_driver); +} +module_init(of_gpio_leds_init); + +static void __exit of_gpio_leds_exit(void) +{ + of_unregister_platform_driver(&of_gpio_leds_driver); +} +module_exit(of_gpio_leds_exit); + +MODULE_DESCRIPTION("OpenFirmware bindings for GPIO connected LEDs"); +MODULE_AUTHOR("Anton Vorontsov "); +MODULE_LICENSE("GPL"); -- 1.5.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/