Commit 3ddab478 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds

* 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds:
  leds: Add mx31moboard MC13783 led support
  leds: Add mc13783 LED support
  leds: leds-ss4200: fix led_classdev_unregister twice in error handling
  leds: leds-lp3944: properly handle lp3944_configure fail in lp3944_probe
  leds: led-class: set permissions on max_brightness file to 0444
  leds: leds-gpio: Change blink_set callback to be able to turn off blinking
  leds: Add LED driver for the Soekris net5501 board
  leds: 88pm860x - fix checking in probe function
parents d1e0fe25 a7cca8ae
...@@ -220,11 +220,54 @@ static struct mc13783_regulator_init_data moboard_regulators[] = { ...@@ -220,11 +220,54 @@ static struct mc13783_regulator_init_data moboard_regulators[] = {
}, },
}; };
static struct mc13783_led_platform_data moboard_led[] = {
{
.id = MC13783_LED_R1,
.name = "coreboard-led-4:red",
.max_current = 2,
},
{
.id = MC13783_LED_G1,
.name = "coreboard-led-4:green",
.max_current = 2,
},
{
.id = MC13783_LED_B1,
.name = "coreboard-led-4:blue",
.max_current = 2,
},
{
.id = MC13783_LED_R2,
.name = "coreboard-led-5:red",
.max_current = 3,
},
{
.id = MC13783_LED_G2,
.name = "coreboard-led-5:green",
.max_current = 3,
},
{
.id = MC13783_LED_B2,
.name = "coreboard-led-5:blue",
.max_current = 3,
},
};
static struct mc13783_leds_platform_data moboard_leds = {
.num_leds = ARRAY_SIZE(moboard_led),
.led = moboard_led,
.flags = MC13783_LED_SLEWLIMTC,
.abmode = MC13783_LED_AB_DISABLED,
.tc1_period = MC13783_LED_PERIOD_10MS,
.tc2_period = MC13783_LED_PERIOD_10MS,
};
static struct mc13783_platform_data moboard_pmic = { static struct mc13783_platform_data moboard_pmic = {
.regulators = moboard_regulators, .regulators = moboard_regulators,
.num_regulators = ARRAY_SIZE(moboard_regulators), .num_regulators = ARRAY_SIZE(moboard_regulators),
.leds = &moboard_leds,
.flags = MC13783_USE_REGULATOR | MC13783_USE_RTC | .flags = MC13783_USE_REGULATOR | MC13783_USE_RTC |
MC13783_USE_ADC, MC13783_USE_ADC | MC13783_USE_LED,
}; };
static struct spi_board_info moboard_spi_board_info[] __initdata = { static struct spi_board_info moboard_spi_board_info[] __initdata = {
......
...@@ -240,22 +240,23 @@ static int __init dns323_read_mac_addr(void) ...@@ -240,22 +240,23 @@ static int __init dns323_read_mac_addr(void)
#define ORION_BLINK_HALF_PERIOD 100 /* ms */ #define ORION_BLINK_HALF_PERIOD 100 /* ms */
static int dns323_gpio_blink_set(unsigned gpio, static int dns323_gpio_blink_set(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_off) unsigned long *delay_on, unsigned long *delay_off)
{ {
static int value = 0;
if (!*delay_on && !*delay_off) if (delay_on && delay_off && !*delay_on && !*delay_off)
*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD; *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
if (ORION_BLINK_HALF_PERIOD == *delay_on switch(state) {
&& ORION_BLINK_HALF_PERIOD == *delay_off) { case GPIO_LED_NO_BLINK_LOW:
value = !value; case GPIO_LED_NO_BLINK_HIGH:
orion_gpio_set_blink(gpio, value); orion_gpio_set_blink(gpio, 0);
return 0; gpio_set_value(gpio, state);
break;
case GPIO_LED_BLINK:
orion_gpio_set_blink(gpio, 1);
} }
return 0;
return -EINVAL;
} }
static struct gpio_led dns323_leds[] = { static struct gpio_led dns323_leds[] = {
...@@ -263,6 +264,7 @@ static struct gpio_led dns323_leds[] = { ...@@ -263,6 +264,7 @@ static struct gpio_led dns323_leds[] = {
.name = "power:blue", .name = "power:blue",
.gpio = DNS323_GPIO_LED_POWER2, .gpio = DNS323_GPIO_LED_POWER2,
.default_trigger = "timer", .default_trigger = "timer",
.active_low = 1,
}, { }, {
.name = "right:amber", .name = "right:amber",
.gpio = DNS323_GPIO_LED_RIGHT_AMBER, .gpio = DNS323_GPIO_LED_RIGHT_AMBER,
......
...@@ -67,6 +67,16 @@ config LEDS_NET48XX ...@@ -67,6 +67,16 @@ config LEDS_NET48XX
This option enables support for the Soekris net4801 and net4826 error This option enables support for the Soekris net4801 and net4826 error
LED. LED.
config LEDS_NET5501
tristate "LED Support for Soekris net5501 series Error LED"
depends on LEDS_CLASS && LEDS_TRIGGERS
depends on LEDS_GPIO_PLATFORM && GPIO_CS5535
select LEDS_TRIGGER_DEFAULT_ON
default n
help
Add support for the Soekris net5501 board (detection, error led
and GPIO).
config LEDS_FSG config LEDS_FSG
tristate "LED Support for the Freecom FSG-3" tristate "LED Support for the Freecom FSG-3"
depends on MACH_FSG depends on MACH_FSG
...@@ -285,6 +295,13 @@ config LEDS_DELL_NETBOOKS ...@@ -285,6 +295,13 @@ config LEDS_DELL_NETBOOKS
This adds support for the Latitude 2100 and similar This adds support for the Latitude 2100 and similar
notebooks that have an external LED. notebooks that have an external LED.
config LEDS_MC13783
tristate "LED Support for MC13783 PMIC"
depends on MFD_MC13783
help
This option enable support for on-chip LED drivers found
on Freescale Semiconductor MC13783 PMIC.
config LEDS_TRIGGERS config LEDS_TRIGGERS
bool "LED Trigger support" bool "LED Trigger support"
help help
......
...@@ -13,6 +13,7 @@ obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o ...@@ -13,6 +13,7 @@ obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
...@@ -35,6 +36,7 @@ obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o ...@@ -35,6 +36,7 @@ obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
# LED SPI Drivers # LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
......
...@@ -74,7 +74,7 @@ static ssize_t led_max_brightness_show(struct device *dev, ...@@ -74,7 +74,7 @@ static ssize_t led_max_brightness_show(struct device *dev,
static struct device_attribute led_class_attrs[] = { static struct device_attribute led_class_attrs[] = {
__ATTR(brightness, 0644, led_brightness_show, led_brightness_store), __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
__ATTR(max_brightness, 0644, led_max_brightness_show, NULL), __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS #ifdef CONFIG_LEDS_TRIGGERS
__ATTR(trigger, 0644, led_trigger_show, led_trigger_store), __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
#endif #endif
......
...@@ -256,8 +256,10 @@ static int pm860x_led_probe(struct platform_device *pdev) ...@@ -256,8 +256,10 @@ static int pm860x_led_probe(struct platform_device *pdev)
if (pdev->dev.parent->platform_data) { if (pdev->dev.parent->platform_data) {
pm860x_pdata = pdev->dev.parent->platform_data; pm860x_pdata = pdev->dev.parent->platform_data;
pdata = pm860x_pdata->led; pdata = pm860x_pdata->led;
} else } else {
pdata = NULL; dev_err(&pdev->dev, "missing platform data\n");
return -EINVAL;
}
data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL); data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
if (data == NULL) if (data == NULL)
...@@ -268,8 +270,11 @@ static int pm860x_led_probe(struct platform_device *pdev) ...@@ -268,8 +270,11 @@ static int pm860x_led_probe(struct platform_device *pdev)
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
data->iset = pdata->iset; data->iset = pdata->iset;
data->port = __check_device(pdata, data->name); data->port = __check_device(pdata, data->name);
if (data->port < 0) if (data->port < 0) {
dev_err(&pdev->dev, "check device failed\n");
kfree(data);
return -EINVAL; return -EINVAL;
}
data->current_brightness = 0; data->current_brightness = 0;
data->cdev.name = data->name; data->cdev.name = data->name;
......
...@@ -26,7 +26,8 @@ struct gpio_led_data { ...@@ -26,7 +26,8 @@ struct gpio_led_data {
u8 new_level; u8 new_level;
u8 can_sleep; u8 can_sleep;
u8 active_low; u8 active_low;
int (*platform_gpio_blink_set)(unsigned gpio, u8 blinking;
int (*platform_gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_off); unsigned long *delay_on, unsigned long *delay_off);
}; };
...@@ -35,6 +36,12 @@ static void gpio_led_work(struct work_struct *work) ...@@ -35,6 +36,12 @@ static void gpio_led_work(struct work_struct *work)
struct gpio_led_data *led_dat = struct gpio_led_data *led_dat =
container_of(work, struct gpio_led_data, work); container_of(work, struct gpio_led_data, work);
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpio,
led_dat->new_level,
NULL, NULL);
led_dat->blinking = 0;
} else
gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level); gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
} }
...@@ -60,8 +67,14 @@ static void gpio_led_set(struct led_classdev *led_cdev, ...@@ -60,8 +67,14 @@ static void gpio_led_set(struct led_classdev *led_cdev,
if (led_dat->can_sleep) { if (led_dat->can_sleep) {
led_dat->new_level = level; led_dat->new_level = level;
schedule_work(&led_dat->work); schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpio, level,
NULL, NULL);
led_dat->blinking = 0;
} else } else
gpio_set_value(led_dat->gpio, level); gpio_set_value(led_dat->gpio, level);
}
} }
static int gpio_blink_set(struct led_classdev *led_cdev, static int gpio_blink_set(struct led_classdev *led_cdev,
...@@ -70,12 +83,14 @@ static int gpio_blink_set(struct led_classdev *led_cdev, ...@@ -70,12 +83,14 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
struct gpio_led_data *led_dat = struct gpio_led_data *led_dat =
container_of(led_cdev, struct gpio_led_data, cdev); container_of(led_cdev, struct gpio_led_data, cdev);
return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off); led_dat->blinking = 1;
return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
delay_on, delay_off);
} }
static int __devinit create_gpio_led(const struct gpio_led *template, static int __devinit create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent, struct gpio_led_data *led_dat, struct device *parent,
int (*blink_set)(unsigned, unsigned long *, unsigned long *)) int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
{ {
int ret, state; int ret, state;
...@@ -97,6 +112,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template, ...@@ -97,6 +112,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
led_dat->gpio = template->gpio; led_dat->gpio = template->gpio;
led_dat->can_sleep = gpio_cansleep(template->gpio); led_dat->can_sleep = gpio_cansleep(template->gpio);
led_dat->active_low = template->active_low; led_dat->active_low = template->active_low;
led_dat->blinking = 0;
if (blink_set) { if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set; led_dat->platform_gpio_blink_set = blink_set;
led_dat->cdev.blink_set = gpio_blink_set; led_dat->cdev.blink_set = gpio_blink_set;
...@@ -234,6 +250,7 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev, ...@@ -234,6 +250,7 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
led.gpio = of_get_gpio_flags(child, 0, &flags); led.gpio = of_get_gpio_flags(child, 0, &flags);
led.active_low = flags & OF_GPIO_ACTIVE_LOW; led.active_low = flags & OF_GPIO_ACTIVE_LOW;
led.name = of_get_property(child, "label", NULL) ? : child->name; led.name = of_get_property(child, "label", NULL) ? : child->name;
led.blinking = 0;
led.default_trigger = led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL); of_get_property(child, "linux,default-trigger", NULL);
state = of_get_property(child, "default-state", NULL); state = of_get_property(child, "default-state", NULL);
......
...@@ -379,6 +379,7 @@ static int __devinit lp3944_probe(struct i2c_client *client, ...@@ -379,6 +379,7 @@ static int __devinit lp3944_probe(struct i2c_client *client,
{ {
struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data; struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
struct lp3944_data *data; struct lp3944_data *data;
int err;
if (lp3944_pdata == NULL) { if (lp3944_pdata == NULL) {
dev_err(&client->dev, "no platform data\n"); dev_err(&client->dev, "no platform data\n");
...@@ -401,9 +402,13 @@ static int __devinit lp3944_probe(struct i2c_client *client, ...@@ -401,9 +402,13 @@ static int __devinit lp3944_probe(struct i2c_client *client,
mutex_init(&data->lock); mutex_init(&data->lock);
dev_info(&client->dev, "lp3944 enabled\n"); err = lp3944_configure(client, data, lp3944_pdata);
if (err < 0) {
kfree(data);
return err;
}
lp3944_configure(client, data, lp3944_pdata); dev_info(&client->dev, "lp3944 enabled\n");
return 0; return 0;
} }
......
/*
* LEDs driver for Freescale MC13783
*
* Copyright (C) 2010 Philippe Rétornaz
*
* Based on leds-da903x:
* Copyright (C) 2008 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
*
* 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/mfd/mc13783.h>
#include <linux/slab.h>
struct mc13783_led {
struct led_classdev cdev;
struct work_struct work;
struct mc13783 *master;
enum led_brightness new_brightness;
int id;
};
#define MC13783_REG_LED_CONTROL_0 51
#define MC13783_LED_C0_ENABLE_BIT (1 << 0)
#define MC13783_LED_C0_TRIODE_MD_BIT (1 << 7)
#define MC13783_LED_C0_TRIODE_AD_BIT (1 << 8)
#define MC13783_LED_C0_TRIODE_KP_BIT (1 << 9)
#define MC13783_LED_C0_BOOST_BIT (1 << 10)
#define MC13783_LED_C0_ABMODE_MASK 0x7
#define MC13783_LED_C0_ABMODE 11
#define MC13783_LED_C0_ABREF_MASK 0x3
#define MC13783_LED_C0_ABREF 14
#define MC13783_REG_LED_CONTROL_1 52
#define MC13783_LED_C1_TC1HALF_BIT (1 << 18)
#define MC13783_REG_LED_CONTROL_2 53
#define MC13783_LED_C2_BL_P_MASK 0xf
#define MC13783_LED_C2_MD_P 9
#define MC13783_LED_C2_AD_P 13
#define MC13783_LED_C2_KP_P 17
#define MC13783_LED_C2_BL_C_MASK 0x7
#define MC13783_LED_C2_MD_C 0
#define MC13783_LED_C2_AD_C 3
#define MC13783_LED_C2_KP_C 6
#define MC13783_REG_LED_CONTROL_3 54
#define MC13783_LED_C3_TC_P 6
#define MC13783_LED_C3_TC_P_MASK 0x1f
#define MC13783_REG_LED_CONTROL_4 55
#define MC13783_REG_LED_CONTROL_5 56
#define MC13783_LED_Cx_PERIOD 21
#define MC13783_LED_Cx_PERIOD_MASK 0x3
#define MC13783_LED_Cx_SLEWLIM_BIT (1 << 23)
#define MC13783_LED_Cx_TRIODE_TC_BIT (1 << 23)
#define MC13783_LED_Cx_TC_C_MASK 0x3
static void mc13783_led_work(struct work_struct *work)
{
struct mc13783_led *led = container_of(work, struct mc13783_led, work);
int reg = 0;
int mask = 0;
int value = 0;
int bank, off, shift;
switch (led->id) {
case MC13783_LED_MD:
reg = MC13783_REG_LED_CONTROL_2;
mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_MD_P;
value = (led->new_brightness >> 4) << MC13783_LED_C2_MD_P;
break;
case MC13783_LED_AD:
reg = MC13783_REG_LED_CONTROL_2;
mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_AD_P;
value = (led->new_brightness >> 4) << MC13783_LED_C2_AD_P;
break;
case MC13783_LED_KP:
reg = MC13783_REG_LED_CONTROL_2;
mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_KP_P;
value = (led->new_brightness >> 4) << MC13783_LED_C2_KP_P;
break;
case MC13783_LED_R1:
case MC13783_LED_G1:
case MC13783_LED_B1:
case MC13783_LED_R2:
case MC13783_LED_G2:
case MC13783_LED_B2:
case MC13783_LED_R3:
case MC13783_LED_G3:
case MC13783_LED_B3:
off = led->id - MC13783_LED_R1;
bank = off/3;
reg = MC13783_REG_LED_CONTROL_3 + off/3;
shift = (off - bank * 3) * 5 + MC13783_LED_C3_TC_P;
value = (led->new_brightness >> 3) << shift;
mask = MC13783_LED_C3_TC_P_MASK << shift;
break;
}
mc13783_lock(led->master);
mc13783_reg_rmw(led->master, reg, mask, value);
mc13783_unlock(led->master);
}
static void mc13783_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct mc13783_led *led;
led = container_of(led_cdev, struct mc13783_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
}
static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
{
int shift = 0;
int mask = 0;
int value = 0;
int reg = 0;
int ret, bank;
switch (led->id) {
case MC13783_LED_MD:
shift = MC13783_LED_C2_MD_C;
mask = MC13783_LED_C2_BL_C_MASK;
value = max_current & MC13783_LED_C2_BL_C_MASK;
reg = MC13783_REG_LED_CONTROL_2;
break;
case MC13783_LED_AD:
shift = MC13783_LED_C2_AD_C;
mask = MC13783_LED_C2_BL_C_MASK;
value = max_current & MC13783_LED_C2_BL_C_MASK;
reg = MC13783_REG_LED_CONTROL_2;
break;
case MC13783_LED_KP:
shift = MC13783_LED_C2_KP_C;
mask = MC13783_LED_C2_BL_C_MASK;
value = max_current & MC13783_LED_C2_BL_C_MASK;
reg = MC13783_REG_LED_CONTROL_2;
break;
case MC13783_LED_R1:
case MC13783_LED_G1:
case MC13783_LED_B1:
case MC13783_LED_R2:
case MC13783_LED_G2:
case MC13783_LED_B2:
case MC13783_LED_R3:
case MC13783_LED_G3:
case MC13783_LED_B3:
bank = (led->id - MC13783_LED_R1)/3;
reg = MC13783_REG_LED_CONTROL_3 + bank;
shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2;
mask = MC13783_LED_Cx_TC_C_MASK;
value = max_current & MC13783_LED_Cx_TC_C_MASK;
break;
}
mc13783_lock(led->master);
ret = mc13783_reg_rmw(led->master, reg, mask << shift,
value << shift);
mc13783_unlock(led->master);
return ret;
}
static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
{
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
int ret = 0;
int reg = 0;
mc13783_lock(dev);
if (pdata->flags & MC13783_LED_TC1HALF)
reg |= MC13783_LED_C1_TC1HALF_BIT;
if (pdata->flags & MC13783_LED_SLEWLIMTC)
reg |= MC13783_LED_Cx_SLEWLIM_BIT;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_1, reg);
if (ret)
goto out;
reg = (pdata->bl_period & MC13783_LED_Cx_PERIOD_MASK) <<
MC13783_LED_Cx_PERIOD;
if (pdata->flags & MC13783_LED_SLEWLIMBL)
reg |= MC13783_LED_Cx_SLEWLIM_BIT;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_2, reg);
if (ret)
goto out;
reg = (pdata->tc1_period & MC13783_LED_Cx_PERIOD_MASK) <<
MC13783_LED_Cx_PERIOD;
if (pdata->flags & MC13783_LED_TRIODE_TC1)
reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_3, reg);
if (ret)
goto out;
reg = (pdata->tc2_period & MC13783_LED_Cx_PERIOD_MASK) <<
MC13783_LED_Cx_PERIOD;
if (pdata->flags & MC13783_LED_TRIODE_TC2)
reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_4, reg);
if (ret)
goto out;
reg = (pdata->tc3_period & MC13783_LED_Cx_PERIOD_MASK) <<
MC13783_LED_Cx_PERIOD;
if (pdata->flags & MC13783_LED_TRIODE_TC3)
reg |= MC13783_LED_Cx_TRIODE_TC_BIT;;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg);
if (ret)
goto out;
reg = MC13783_LED_C0_ENABLE_BIT;
if (pdata->flags & MC13783_LED_TRIODE_MD)
reg |= MC13783_LED_C0_TRIODE_MD_BIT;
if (pdata->flags & MC13783_LED_TRIODE_AD)
reg |= MC13783_LED_C0_TRIODE_AD_BIT;
if (pdata->flags & MC13783_LED_TRIODE_KP)
reg |= MC13783_LED_C0_TRIODE_KP_BIT;
if (pdata->flags & MC13783_LED_BOOST_EN)
reg |= MC13783_LED_C0_BOOST_BIT;
reg |= (pdata->abmode & MC13783_LED_C0_ABMODE_MASK) <<
MC13783_LED_C0_ABMODE;
reg |= (pdata->abref & MC13783_LED_C0_ABREF_MASK) <<
MC13783_LED_C0_ABREF;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_0, reg);
out:
mc13783_unlock(dev);
return ret;
}
static int __devinit mc13783_led_probe(struct platform_device *pdev)
{
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13783_led_platform_data *led_cur;
struct mc13783_led *led, *led_dat;
int ret, i;
int init_led = 0;
if (pdata == NULL) {
dev_err(&pdev->dev, "missing platform data\n");
return -ENODEV;
}
if (pdata->num_leds < 1 || pdata->num_leds > MC13783_LED_MAX) {
dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds);
return -EINVAL;
}
led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
if (led == NULL) {
dev_err(&pdev->dev, "failed to alloc memory\n");
return -ENOMEM;
}
ret = mc13783_leds_prepare(pdev);
if (ret) {
dev_err(&pdev->dev, "unable to init led driver\n");
goto err_free;
}
for (i = 0; i < pdata->num_leds; i++) {
led_dat = &led[i];
led_cur = &pdata->led[i];
if (led_cur->id > MC13783_LED_MAX || led_cur->id < 0) {
dev_err(&pdev->dev, "invalid id %d\n", led_cur->id);
ret = -EINVAL;
goto err_register;
}
if (init_led & (1 << led_cur->id)) {
dev_err(&pdev->dev, "led %d already initialized\n",
led_cur->id);
ret = -EINVAL;
goto err_register;
}
init_led |= 1 << led_cur->id;
led_dat->cdev.name = led_cur->name;
led_dat->cdev.default_trigger = led_cur->default_trigger;
led_dat->cdev.brightness_set = mc13783_led_set;
led_dat->cdev.brightness = LED_OFF;
led_dat->id = led_cur->id;
led_dat->master = dev_get_drvdata(pdev->dev.parent);
INIT_WORK(&led_dat->work, mc13783_led_work);
ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register led %d\n",
led_dat->id);
goto err_register;
}
ret = mc13783_led_setup(led_dat, led_cur->max_current);
if (ret) {
dev_err(&pdev->dev, "unable to init led %d\n",
led_dat->id);
i++;
goto err_register;
}
}
platform_set_drvdata(pdev, led);
return 0;
err_register:
for (i = i - 1; i >= 0; i--) {
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
err_free:
kfree(led);
return ret;
}
static int __devexit mc13783_led_remove(struct platform_device *pdev)
{
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13783_led *led = platform_get_drvdata(pdev);
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
int i;
for (i = 0; i < pdata->num_leds; i++) {
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
mc13783_lock(dev);
mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_0, 0);
mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_1, 0);
mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_2, 0);
mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_3, 0);
mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_4, 0);
mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_5, 0);
mc13783_unlock(dev);
kfree(led);
return 0;
}
static struct platform_driver mc13783_led_driver = {
.driver = {
.name = "mc13783-led",
.owner = THIS_MODULE,
},
.probe = mc13783_led_probe,
.remove = __devexit_p(mc13783_led_remove),
};
static int __init mc13783_led_init(void)
{
return platform_driver_register(&mc13783_led_driver);
}
module_init(mc13783_led_init);
static void __exit mc13783_led_exit(void)
{
platform_driver_unregister(&mc13783_led_driver);
}
module_exit(mc13783_led_exit);
MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC");
MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mc13783-led");
/*
* Soekris board support code
*
* Copyright (C) 2008-2009 Tower Technologies
* Written by Alessandro Zummo <a.zummo@towertech.it>
*
* 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 <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/string.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/geode.h>
static struct gpio_led net5501_leds[] = {
{
.name = "error",
.gpio = 6,
.default_trigger = "default-on",
},
};
static struct gpio_led_platform_data net5501_leds_data = {
.num_leds = ARRAY_SIZE(net5501_leds),
.leds = net5501_leds,
};
static struct platform_device net5501_leds_dev = {
.name = "leds-gpio",
.id = -1,
.dev.platform_data = &net5501_leds_data,
};
static void __init init_net5501(void)
{
platform_device_register(&net5501_leds_dev);
}
struct soekris_board {
u16 offset;
char *sig;
u8 len;
void (*init)(void);
};
static struct soekris_board __initdata boards[] = {
{ 0xb7b, "net5501", 7, init_net5501 }, /* net5501 v1.33/1.33c */
{ 0xb1f, "net5501", 7, init_net5501 }, /* net5501 v1.32i */
};
static int __init soekris_init(void)
{
int i;
unsigned char *rombase, *bios;
if (!is_geode())
return 0;
rombase = ioremap(0xffff0000, 0xffff);
if (!rombase) {
printk(KERN_INFO "Soekris net5501 LED driver failed to get rombase");
return 0;
}
bios = rombase + 0x20; /* null terminated */
if (strncmp(bios, "comBIOS", 7))
goto unmap;
for (i = 0; i < ARRAY_SIZE(boards); i++) {
unsigned char *model = rombase + boards[i].offset;
if (strncmp(model, boards[i].sig, boards[i].len) == 0) {
printk(KERN_INFO "Soekris %s: %s\n", model, bios);
if (boards[i].init)
boards[i].init();
break;
}
}
unmap:
iounmap(rombase);
return 0;
}
arch_initcall(soekris_init);
...@@ -534,7 +534,7 @@ static int __init nas_gpio_init(void) ...@@ -534,7 +534,7 @@ static int __init nas_gpio_init(void)
set_power_light_amber_noblink(); set_power_light_amber_noblink();
return 0; return 0;
out_err: out_err:
for (; i >= 0; i--) for (i--; i >= 0; i--)
unregister_nasgpio_led(i); unregister_nasgpio_led(i);
pci_unregister_driver(&nas_gpio_pci_driver); pci_unregister_driver(&nas_gpio_pci_driver);
return ret; return ret;
......
...@@ -679,6 +679,10 @@ static int mc13783_probe(struct spi_device *spi) ...@@ -679,6 +679,10 @@ static int mc13783_probe(struct spi_device *spi)
if (pdata->flags & MC13783_USE_TOUCHSCREEN) if (pdata->flags & MC13783_USE_TOUCHSCREEN)
mc13783_add_subdevice(mc13783, "mc13783-ts"); mc13783_add_subdevice(mc13783, "mc13783-ts");
if (pdata->flags & MC13783_USE_LED)
mc13783_add_subdevice_pdata(mc13783, "mc13783-led",
pdata->leds, sizeof(*pdata->leds));
return 0; return 0;
} }
......
...@@ -156,7 +156,11 @@ struct gpio_led { ...@@ -156,7 +156,11 @@ struct gpio_led {
struct gpio_led_platform_data { struct gpio_led_platform_data {
int num_leds; int num_leds;
struct gpio_led *leds; struct gpio_led *leds;
int (*gpio_blink_set)(unsigned gpio,
#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
#define GPIO_LED_BLINK 2 /* Plase, blink */
int (*gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_on,
unsigned long *delay_off); unsigned long *delay_off);
}; };
......
...@@ -64,6 +64,70 @@ static inline int mc13783_ackirq(struct mc13783 *mc13783, int irq) ...@@ -64,6 +64,70 @@ static inline int mc13783_ackirq(struct mc13783 *mc13783, int irq)
MC13783_ADC0_TSMOD1 | \ MC13783_ADC0_TSMOD1 | \
MC13783_ADC0_TSMOD2) MC13783_ADC0_TSMOD2)
struct mc13783_led_platform_data {
#define MC13783_LED_MD 0
#define MC13783_LED_AD 1
#define MC13783_LED_KP 2
#define MC13783_LED_R1 3
#define MC13783_LED_G1 4
#define MC13783_LED_B1 5
#define MC13783_LED_R2 6
#define MC13783_LED_G2 7
#define MC13783_LED_B2 8
#define MC13783_LED_R3 9
#define MC13783_LED_G3 10
#define MC13783_LED_B3 11
#define MC13783_LED_MAX MC13783_LED_B3
int id;
const char *name;
const char *default_trigger;
/* Three or two bits current selection depending on the led */
char max_current;
};
struct mc13783_leds_platform_data {
int num_leds;
struct mc13783_led_platform_data *led;
#define MC13783_LED_TRIODE_MD (1 << 0)
#define MC13783_LED_TRIODE_AD (1 << 1)
#define MC13783_LED_TRIODE_KP (1 << 2)
#define MC13783_LED_BOOST_EN (1 << 3)
#define MC13783_LED_TC1HALF (1 << 4)
#define MC13783_LED_SLEWLIMTC (1 << 5)
#define MC13783_LED_SLEWLIMBL (1 << 6)
#define MC13783_LED_TRIODE_TC1 (1 << 7)
#define MC13783_LED_TRIODE_TC2 (1 << 8)
#define MC13783_LED_TRIODE_TC3 (1 << 9)
int flags;
#define MC13783_LED_AB_DISABLED 0
#define MC13783_LED_AB_MD1 1
#define MC13783_LED_AB_MD12 2
#define MC13783_LED_AB_MD123 3
#define MC13783_LED_AB_MD1234 4
#define MC13783_LED_AB_MD1234_AD1 5
#define MC13783_LED_AB_MD1234_AD12 6
#define MC13783_LED_AB_MD1_AD 7
char abmode;
#define MC13783_LED_ABREF_200MV 0
#define MC13783_LED_ABREF_400MV 1
#define MC13783_LED_ABREF_600MV 2
#define MC13783_LED_ABREF_800MV 3
char abref;
#define MC13783_LED_PERIOD_10MS 0
#define MC13783_LED_PERIOD_100MS 1
#define MC13783_LED_PERIOD_500MS 2
#define MC13783_LED_PERIOD_2S 3
char bl_period;
char tc1_period;
char tc2_period;
char tc3_period;
};
/* to be cleaned up */ /* to be cleaned up */
struct regulator_init_data; struct regulator_init_data;
...@@ -80,12 +144,14 @@ struct mc13783_regulator_platform_data { ...@@ -80,12 +144,14 @@ struct mc13783_regulator_platform_data {
struct mc13783_platform_data { struct mc13783_platform_data {
int num_regulators; int num_regulators;
struct mc13783_regulator_init_data *regulators; struct mc13783_regulator_init_data *regulators;
struct mc13783_leds_platform_data *leds;
#define MC13783_USE_TOUCHSCREEN (1 << 0) #define MC13783_USE_TOUCHSCREEN (1 << 0)
#define MC13783_USE_CODEC (1 << 1) #define MC13783_USE_CODEC (1 << 1)
#define MC13783_USE_ADC (1 << 2) #define MC13783_USE_ADC (1 << 2)
#define MC13783_USE_RTC (1 << 3) #define MC13783_USE_RTC (1 << 3)
#define MC13783_USE_REGULATOR (1 << 4) #define MC13783_USE_REGULATOR (1 << 4)
#define MC13783_USE_LED (1 << 5)
unsigned int flags; unsigned int flags;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment