778 lines
19 KiB
C
778 lines
19 KiB
C
/* include/asm/mach-msm/leds-microp.c
|
|
*
|
|
* Copyright (C) 2009 HTC Corporation.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#ifdef CONFIG_MICROP_COMMON
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/leds.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/platform_device.h>
|
|
#include <mach/atmega_microp.h>
|
|
|
|
static int microp_write_led_mode(struct led_classdev *led_cdev,
|
|
uint8_t mode, uint16_t off_timer)
|
|
{
|
|
struct microp_led_data *ldata;
|
|
uint8_t data[7];
|
|
int ret;
|
|
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
if (!strcmp(ldata->ldev.name, "green")) {
|
|
data[0] = 0x01;
|
|
data[1] = mode;
|
|
data[2] = off_timer >> 8;
|
|
data[3] = off_timer & 0xFF;
|
|
data[4] = 0x00;
|
|
data[5] = 0x00;
|
|
data[6] = 0x00;
|
|
} else if (!strcmp(ldata->ldev.name, "amber")) {
|
|
data[0] = 0x02;
|
|
data[1] = 0x00;
|
|
data[2] = 0x00;
|
|
data[3] = 0x00;
|
|
data[4] = mode;
|
|
data[5] = off_timer >> 8;
|
|
data[6] = off_timer & 0xFF;
|
|
} else if (!strcmp(ldata->ldev.name, "blue")) {
|
|
data[0] = 0x04;
|
|
data[1] = mode;
|
|
data[2] = off_timer >> 8;
|
|
data[3] = off_timer & 0xFF;
|
|
data[4] = 0x00;
|
|
data[5] = 0x00;
|
|
data[6] = 0x00;
|
|
}
|
|
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_LED_MODE, data, 7);
|
|
if (ret == 0) {
|
|
mutex_lock(&ldata->led_data_mutex);
|
|
if (mode > 1)
|
|
ldata->blink = mode;
|
|
ldata->mode = mode;
|
|
mutex_unlock(&ldata->led_data_mutex);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void microp_led_brightness_set(struct led_classdev *led_cdev,
|
|
enum led_brightness brightness)
|
|
{
|
|
struct microp_led_data *ldata;
|
|
unsigned long flags;
|
|
int ret;
|
|
uint8_t mode;
|
|
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
if (brightness > 255)
|
|
brightness = 255;
|
|
led_cdev->brightness = brightness;
|
|
|
|
spin_lock_irqsave(&ldata->brightness_lock, flags);
|
|
ldata->brightness = brightness;
|
|
spin_unlock_irqrestore(&ldata->brightness_lock, flags);
|
|
|
|
if (brightness)
|
|
mode = 1;
|
|
else
|
|
mode = 0;
|
|
|
|
ret = microp_write_led_mode(led_cdev, mode, 0xffff);
|
|
if (ret)
|
|
pr_err("%s: led_brightness_set failed to set mode\n", __func__);
|
|
}
|
|
|
|
static void microp_led_jogball_brightness_set(struct led_classdev *led_cdev,
|
|
enum led_brightness brightness)
|
|
{
|
|
struct microp_led_data *ldata;
|
|
unsigned long flags;
|
|
uint8_t data[3] = {0, 0, 0};
|
|
int ret = 0;
|
|
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
spin_lock_irqsave(&ldata->brightness_lock, flags);
|
|
ldata->brightness = brightness;
|
|
spin_unlock_irqrestore(&ldata->brightness_lock, flags);
|
|
|
|
switch (brightness) {
|
|
case 0:
|
|
data[0] = 0;
|
|
break;
|
|
case 1:
|
|
data[0] = 3;
|
|
data[1] = data[2] = 0xFF;
|
|
break;
|
|
case 3:
|
|
data[0] = 1;
|
|
data[1] = data[2] = 0xFF;
|
|
break;
|
|
case 7:
|
|
data[0] = 2;
|
|
data[1] = 0;
|
|
data[2] = 60;
|
|
break;
|
|
default:
|
|
pr_warning("%s: unknown value: %d\n", __func__, brightness);
|
|
break;
|
|
}
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_JOGBALL_LED_MODE, data, 3);
|
|
if (ret < 0)
|
|
pr_err("%s failed on set jogball mode:0x%2.2X\n", __func__, data[0]);
|
|
}
|
|
|
|
static void microp_led_mobeam_brightness_set(struct led_classdev *led_cdev,
|
|
enum led_brightness brightness)
|
|
{
|
|
;
|
|
}
|
|
|
|
static void microp_led_wimax_brightness_set(struct led_classdev *led_cdev,
|
|
enum led_brightness brightness)
|
|
{
|
|
struct microp_led_data *ldata;
|
|
unsigned long flags;
|
|
uint8_t data[3] = {0, 0, 0};
|
|
int ret = 0;
|
|
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
spin_lock_irqsave(&ldata->brightness_lock, flags);
|
|
ldata->brightness = brightness;
|
|
spin_unlock_irqrestore(&ldata->brightness_lock, flags);
|
|
|
|
switch (brightness) {
|
|
case 0:
|
|
data[0] = 0;
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 129:
|
|
case 130:
|
|
case 131:
|
|
data[0] = brightness;
|
|
data[1] = data[2] = 0xFF;
|
|
break;
|
|
default:
|
|
pr_warning("%s: unknown value: %d\n", __func__, brightness);
|
|
break;
|
|
}
|
|
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_JOGBALL_LED_MODE, data, 3);
|
|
if (ret < 0)
|
|
pr_err("%s failed on set wimax mode:0x%2.2X\n", __func__, data[0]);
|
|
}
|
|
|
|
static void microp_led_gpo_brightness_set(struct led_classdev *led_cdev,
|
|
enum led_brightness brightness)
|
|
{
|
|
struct microp_led_data *ldata;
|
|
unsigned long flags;
|
|
uint8_t enable, addr, data[3] = {0, 0, 0};
|
|
int ret = 0;
|
|
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
spin_lock_irqsave(&ldata->brightness_lock, flags);
|
|
ldata->brightness = brightness;
|
|
spin_unlock_irqrestore(&ldata->brightness_lock, flags);
|
|
|
|
enable = brightness ? 1 : 0;
|
|
if (enable)
|
|
addr = MICROP_I2C_WCMD_GPO_LED_STATUS_EN;
|
|
else
|
|
addr = MICROP_I2C_WCMD_GPO_LED_STATUS_DIS;
|
|
data[0] = ldata->led_config->mask_w[0];
|
|
data[1] = ldata->led_config->mask_w[1];
|
|
data[2] = ldata->led_config->mask_w[2];
|
|
ret = microp_i2c_write(addr, data, 3);;
|
|
if (ret < 0)
|
|
pr_err("%s failed on set gpo led mode:%d\n", __func__, brightness);
|
|
}
|
|
|
|
static void microp_led_pwm_brightness_set(struct led_classdev *led_cdev,
|
|
enum led_brightness brightness)
|
|
{
|
|
struct microp_led_data *ldata;
|
|
unsigned long flags;
|
|
uint8_t data[4] = {0, 0, 0, 0};
|
|
int ret = 0;
|
|
uint8_t value;
|
|
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
spin_lock_irqsave(&ldata->brightness_lock, flags);
|
|
ldata->brightness = brightness;
|
|
spin_unlock_irqrestore(&ldata->brightness_lock, flags);
|
|
|
|
value = brightness >= 255 ? 0x20 : 0;
|
|
|
|
data[0] = ldata->led_config->fade_time;
|
|
if (brightness)
|
|
data[1] = ldata->led_config->init_value ?
|
|
ldata->led_config->init_value :
|
|
brightness;
|
|
else
|
|
data[1] = 0x00;
|
|
data[2] = ldata->led_config->led_pin >> 8;
|
|
data[3] = ldata->led_config->led_pin;
|
|
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_LED_PWM, data, 4);
|
|
if (ret < 0)
|
|
pr_err("%s failed on set pwm led mode:0x%2.2X\n", __func__, data[1]);
|
|
}
|
|
|
|
static ssize_t microp_led_blink_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct led_classdev *led_cdev;
|
|
struct microp_led_data *ldata;
|
|
int ret;
|
|
|
|
led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
mutex_lock(&ldata->led_data_mutex);
|
|
ret = sprintf(buf, "%d\n", ldata->blink ? ldata->blink - 1 : 0);
|
|
mutex_unlock(&ldata->led_data_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t microp_led_blink_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct led_classdev *led_cdev;
|
|
struct microp_led_data *ldata;
|
|
int val, ret;
|
|
uint8_t mode;
|
|
|
|
val = -1;
|
|
sscanf(buf, "%u", &val);
|
|
if (val < 0 || val > 255)
|
|
return -EINVAL;
|
|
|
|
led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
mutex_lock(&ldata->led_data_mutex);
|
|
switch (val) {
|
|
case 0: /* stop flashing */
|
|
ldata->blink = 0;
|
|
if (led_cdev->brightness)
|
|
mode = 1;
|
|
else
|
|
mode = 0;
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
mode = val + 1;
|
|
break;
|
|
case 4:
|
|
if (!strcmp(ldata->ldev.name, "amber")) {
|
|
mode = val + 1;
|
|
break;
|
|
}
|
|
default:
|
|
mutex_unlock(&ldata->led_data_mutex);
|
|
return -EINVAL;
|
|
}
|
|
mutex_unlock(&ldata->led_data_mutex);
|
|
|
|
ret = microp_write_led_mode(led_cdev, mode, 0xffff);
|
|
if (ret)
|
|
pr_err("%s:%s set blink failed\n", __func__, led_cdev->name);
|
|
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(blink, 0644, microp_led_blink_show,
|
|
microp_led_blink_store);
|
|
|
|
static ssize_t microp_led_off_timer_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct led_classdev *led_cdev;
|
|
struct microp_led_data *ldata;
|
|
uint8_t data[2];
|
|
int ret, offtime;
|
|
|
|
led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
dev_dbg(dev, "Getting %s remaining time\n", led_cdev->name);
|
|
|
|
if (!strcmp(ldata->ldev.name, "green"))
|
|
ret = microp_i2c_read(MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME, data, 2);
|
|
else if (!strcmp(ldata->ldev.name, "amber"))
|
|
ret = microp_i2c_read(MICROP_I2C_RCMD_AMBER_LED_REMAIN_TIME, data, 2);
|
|
else if (!strcmp(ldata->ldev.name, "blue"))
|
|
ret = microp_i2c_read(MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME, data, 2);
|
|
else {
|
|
pr_err("%s: Unknown led %s\n", __func__, ldata->ldev.name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ret)
|
|
pr_err("%s: %s get off_timer failed\n", __func__, led_cdev->name);
|
|
|
|
offtime = (int)((data[1] | data[0] << 8) * 2);
|
|
|
|
ret = sprintf(buf, "Time remains %d:%d\n", offtime / 60, offtime % 60);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t microp_led_off_timer_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct led_classdev *led_cdev;
|
|
struct microp_led_data *ldata;
|
|
int min, sec, ret;
|
|
uint16_t off_timer;
|
|
|
|
min = -1;
|
|
sec = -1;
|
|
sscanf(buf, "%d %d", &min, &sec);
|
|
|
|
if (min < 0 || min > 255)
|
|
return -EINVAL;
|
|
if (sec < 0 || sec > 255)
|
|
return -EINVAL;
|
|
|
|
led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
|
|
dev_dbg(dev, "Setting %s off_timer to %d min %d sec\n",
|
|
led_cdev->name, min, sec);
|
|
|
|
if (!min && !sec)
|
|
off_timer = 0xFFFF;
|
|
else
|
|
off_timer = (min * 60 + sec) / 2;
|
|
|
|
ret = microp_write_led_mode(led_cdev, ldata->mode, off_timer);
|
|
if (ret)
|
|
pr_err("%s: %s set off_timer %d min %d sec failed\n",
|
|
__func__, led_cdev->name, min, sec);
|
|
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(off_timer, 0644, microp_led_off_timer_show,
|
|
microp_led_off_timer_store);
|
|
|
|
static ssize_t microp_jogball_color_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct led_classdev *led_cdev;
|
|
struct microp_led_data *ldata;
|
|
struct i2c_client *client;
|
|
int rpwm, gpwm, bpwm, ret;
|
|
uint8_t data[4];
|
|
|
|
rpwm = -1;
|
|
gpwm = -1;
|
|
bpwm = -1;
|
|
sscanf(buf, "%d %d %d", &rpwm, &gpwm, &bpwm);
|
|
|
|
if (rpwm < 0 || rpwm > 255)
|
|
return -EINVAL;
|
|
if (gpwm < 0 || gpwm > 255)
|
|
return -EINVAL;
|
|
if (bpwm < 0 || bpwm > 255)
|
|
return -EINVAL;
|
|
|
|
led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
|
|
ldata = container_of(led_cdev, struct microp_led_data, ldev);
|
|
client = to_i2c_client(dev->parent);
|
|
|
|
dev_dbg(&client->dev, "Setting %s color to R=%d, G=%d, B=%d\n",
|
|
led_cdev->name, rpwm, gpwm, bpwm);
|
|
|
|
data[0] = rpwm;
|
|
data[1] = gpwm;
|
|
data[2] = bpwm;
|
|
data[3] = 0x00;
|
|
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET, data, 4);
|
|
if (ret) {
|
|
dev_err(&client->dev, "%s set color R=%d G=%d B=%d failed\n",
|
|
led_cdev->name, rpwm, gpwm, bpwm);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(color, 0644, NULL, microp_jogball_color_store);
|
|
|
|
static ssize_t microp_mobeam_read_status_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
uint8_t data[2] = {0, 0};
|
|
int ret;
|
|
pr_info("%s\n", __func__);
|
|
ret = microp_i2c_read(MICROP_I2C_RCMD_MOBEAM_STATUS, data, 2);
|
|
if (ret == 0)
|
|
ret = sprintf(buf, "%d %d\n", data[0], data[1]);
|
|
else
|
|
data[0] = data[1] = 0;
|
|
|
|
return ret;
|
|
}
|
|
static DEVICE_ATTR(read_status, 0444, microp_mobeam_read_status_show, NULL);
|
|
|
|
static ssize_t microp_mobeam_download_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int i, ret, num;
|
|
uint8_t data[73] ; /* Size of cbitstream array MAX 73 bytes. */
|
|
|
|
pr_info("%s\n", __func__);
|
|
memset(data, 0x00, sizeof(data));
|
|
|
|
num = *(buf++);
|
|
if (num < 0 || num > 73)
|
|
return -EINVAL;
|
|
pr_info("%s: count=%d\n", __func__, count);
|
|
for (i = 0; i < count; i++)
|
|
data[i] = *(buf + i);
|
|
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_MOBEAM_DL, data, num);
|
|
if (ret != 0)
|
|
count = 0;
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(data_download, 0644, NULL, microp_mobeam_download_store);
|
|
|
|
static ssize_t microp_mobeam_send_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
uint8_t data[2];
|
|
unsigned char num;
|
|
int ret;
|
|
|
|
pr_info("%s\n", __func__);
|
|
num = *buf;
|
|
|
|
if (num < 0 || num > 73)
|
|
return -EINVAL;
|
|
|
|
data[0] = (uint8_t)num;
|
|
data[1] = 0;
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_MOBEAM_SEND, data, 2);
|
|
if (ret != 0)
|
|
count = 0;
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(send_data, 0644, NULL, microp_mobeam_send_store);
|
|
|
|
static uint8_t leds_data[7];
|
|
|
|
static ssize_t microp_mobeam_enable_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int val;
|
|
uint8_t data[7];
|
|
int ret;
|
|
|
|
pr_info("%s\n", __func__);
|
|
val = -1;
|
|
sscanf(buf, "%u", &val);
|
|
if (val != 1 && val != 0)
|
|
return -EINVAL;
|
|
|
|
if (val) {
|
|
ret = microp_i2c_read(MICROP_I2C_RCMD_LED_STATUS, leds_data, 7);
|
|
data[0] = 0x03;
|
|
data[1] = 0x00;
|
|
data[2] = 0x00;
|
|
data[3] = 0x00;
|
|
data[4] = 0x00;
|
|
data[5] = 0x00;
|
|
data[6] = 0x00;
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_LED_MODE, data, 7);
|
|
pr_info("%s: enabled\n", __func__);
|
|
msleep(150);
|
|
microp_mobeam_enable(1);
|
|
} else {
|
|
microp_mobeam_enable(0);
|
|
ret = microp_i2c_write(MICROP_I2C_WCMD_LED_MODE, leds_data, 7);
|
|
}
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(mobeam_enable, 0644, NULL, microp_mobeam_enable_store);
|
|
|
|
static ssize_t microp_mobeam_stop_led(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int val;
|
|
uint8_t data[2];
|
|
|
|
pr_info("%s\n", __func__);
|
|
val = -1;
|
|
sscanf(buf, "%u", &val);
|
|
|
|
data[0] = 0x00;
|
|
data[1] = 0x01;
|
|
|
|
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(stop_led, 0644, NULL, microp_mobeam_stop_led);
|
|
|
|
|
|
static int microp_led_probe(struct platform_device *pdev)
|
|
{
|
|
struct microp_led_platform_data *pdata;
|
|
struct microp_led_data *ldata;
|
|
int i, ret;
|
|
|
|
pdata = pdev->dev.platform_data;
|
|
if (pdata == NULL) {
|
|
pr_err("%s: platform data is NULL\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
|
|
ldata = kzalloc(sizeof(struct microp_led_data)
|
|
* pdata->num_leds, GFP_KERNEL);
|
|
if (!ldata && pdata->num_leds) {
|
|
ret = -ENOMEM;
|
|
pr_err("%s: failed on allocate ldata\n", __func__);
|
|
goto err_exit;
|
|
}
|
|
|
|
dev_set_drvdata(&pdev->dev, ldata);
|
|
for (i = 0; i < pdata->num_leds; i++) {
|
|
ldata[i].led_config = pdata->led_config + i;
|
|
ldata[i].ldev.name = pdata->led_config[i].name;
|
|
if (pdata->led_config[i].type == LED_JOGBALL)
|
|
ldata[i].ldev.brightness_set
|
|
= microp_led_jogball_brightness_set;
|
|
else if (pdata->led_config[i].type == LED_GPO)
|
|
ldata[i].ldev.brightness_set
|
|
= microp_led_gpo_brightness_set;
|
|
else if (pdata->led_config[i].type == LED_PWM)
|
|
ldata[i].ldev.brightness_set
|
|
= microp_led_pwm_brightness_set;
|
|
else if (pdata->led_config[i].type == LED_RGB)
|
|
ldata[i].ldev.brightness_set
|
|
= microp_led_brightness_set;
|
|
else if (pdata->led_config[i].type == LED_WIMAX)
|
|
ldata[i].ldev.brightness_set
|
|
= microp_led_wimax_brightness_set;
|
|
else if (pdata->led_config[i].type == LED_MOBEAM)
|
|
ldata[i].ldev.brightness_set
|
|
= microp_led_mobeam_brightness_set;
|
|
|
|
mutex_init(&ldata[i].led_data_mutex);
|
|
spin_lock_init(&ldata[i].brightness_lock);
|
|
ret = led_classdev_register(&pdev->dev, &ldata[i].ldev);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on led_classdev_register [%s]\n",
|
|
__func__, ldata[i].ldev.name);
|
|
goto err_register_led_cdev;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pdata->num_leds; i++) {
|
|
if (pdata->led_config[i].type != LED_RGB)
|
|
continue;
|
|
ret = device_create_file(ldata[i].ldev.dev, &dev_attr_blink);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr blink [%d]\n", __func__, i);
|
|
goto err_register_attr_blink;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pdata->num_leds; i++) {
|
|
if (pdata->led_config[i].type != LED_RGB)
|
|
continue;
|
|
ret = device_create_file(ldata[i].ldev.dev, &dev_attr_off_timer);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr off_timer [%d]\n",
|
|
__func__, i);
|
|
goto err_register_attr_off_timer;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < pdata->num_leds; i++) {
|
|
if (pdata->led_config[i].type != LED_JOGBALL)
|
|
continue;
|
|
ret = device_create_file(ldata[i].ldev.dev, &dev_attr_color);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr jogball color\n",
|
|
__func__);
|
|
goto err_register_attr_color;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < pdata->num_leds; i++) {
|
|
if (pdata->led_config[i].type != LED_MOBEAM)
|
|
continue;
|
|
ret = device_create_file(ldata[i].ldev.dev,
|
|
&dev_attr_data_download);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr data download\n",
|
|
__func__);
|
|
goto err_create_mo_download_attr_file;
|
|
}
|
|
|
|
ret = device_create_file(ldata[i].ldev.dev,
|
|
&dev_attr_send_data);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr send data\n",
|
|
__func__);
|
|
goto err_create_mo_send_attr_file;
|
|
}
|
|
|
|
ret = device_create_file(ldata[i].ldev.dev,
|
|
&dev_attr_read_status);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr read status\n",
|
|
__func__);
|
|
goto err_create_mo_read_attr_file;
|
|
}
|
|
|
|
ret = device_create_file(ldata[i].ldev.dev,
|
|
&dev_attr_mobeam_enable);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr enable\n",
|
|
__func__);
|
|
goto err_create_mo_enable_attr_file;
|
|
}
|
|
|
|
ret = device_create_file(ldata[i].ldev.dev,
|
|
&dev_attr_stop_led);
|
|
if (ret < 0) {
|
|
pr_err("%s: failed on create attr stop led\n",
|
|
__func__);
|
|
goto err_create_mo_stop_attr_file;
|
|
}
|
|
break;
|
|
}
|
|
|
|
pr_info("%s: succeeded\n", __func__);
|
|
return 0;
|
|
|
|
err_create_mo_stop_attr_file:
|
|
device_remove_file(ldata[i].ldev.dev, &dev_attr_mobeam_enable);
|
|
err_create_mo_enable_attr_file:
|
|
device_remove_file(ldata[i].ldev.dev, &dev_attr_read_status);
|
|
err_create_mo_read_attr_file:
|
|
device_remove_file(ldata[i].ldev.dev, &dev_attr_send_data);
|
|
err_create_mo_send_attr_file:
|
|
device_remove_file(ldata[i].ldev.dev, &dev_attr_data_download);
|
|
err_create_mo_download_attr_file:
|
|
i = pdata->num_leds;
|
|
err_register_attr_color:
|
|
for (i--; i >= 0; i--) {
|
|
if (pdata->led_config[i].type != LED_JOGBALL)
|
|
continue;
|
|
device_remove_file(ldata[i].ldev.dev, &dev_attr_color);
|
|
}
|
|
i = pdata->num_leds;
|
|
err_register_attr_off_timer:
|
|
for (i--; i >= 0; i--) {
|
|
if (pdata->led_config[i].type != LED_RGB)
|
|
continue;
|
|
device_remove_file(ldata[i].ldev.dev,
|
|
&dev_attr_off_timer);
|
|
}
|
|
i = pdata->num_leds;
|
|
err_register_attr_blink:
|
|
for (i--; i >= 0; i--) {
|
|
if (pdata->led_config[i].type != LED_RGB)
|
|
continue;
|
|
device_remove_file(ldata[i].ldev.dev,
|
|
&dev_attr_blink);
|
|
}
|
|
i = pdata->num_leds;
|
|
|
|
err_register_led_cdev:
|
|
for (i--; i >= 0; i--)
|
|
led_classdev_unregister(&ldata[i].ldev);
|
|
kfree(ldata);
|
|
|
|
err_exit:
|
|
return ret;
|
|
}
|
|
|
|
static int __devexit microp_led_remove(struct platform_device *pdev)
|
|
{
|
|
struct microp_led_platform_data *pdata;
|
|
struct microp_led_data *ldata;
|
|
int i;
|
|
|
|
pdata = pdev->dev.platform_data;
|
|
ldata = platform_get_drvdata(pdev);
|
|
|
|
for (i = 0; i < pdata->num_leds; i++) {
|
|
led_classdev_unregister(&ldata[i].ldev);
|
|
if (pdata->led_config[i].type == LED_RGB) {
|
|
device_remove_file(ldata[i].ldev.dev,
|
|
&dev_attr_off_timer);
|
|
device_remove_file(ldata[i].ldev.dev,
|
|
&dev_attr_blink);
|
|
} else if (pdata->led_config[i].type == LED_JOGBALL)
|
|
device_remove_file(ldata[i].ldev.dev, &dev_attr_color);
|
|
}
|
|
kfree(ldata);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver microp_led_driver = {
|
|
.probe = microp_led_probe,
|
|
.remove = __devexit_p(microp_led_remove),
|
|
.driver = {
|
|
.name = "leds-microp",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
int __init microp_led_init(void)
|
|
{
|
|
return platform_driver_register(µp_led_driver);
|
|
}
|
|
|
|
void microp_led_exit(void)
|
|
{
|
|
platform_driver_unregister(µp_led_driver);
|
|
}
|
|
|
|
module_init(microp_led_init);
|
|
module_exit(microp_led_exit);
|
|
|
|
MODULE_DESCRIPTION("Atmega MicroP led driver");
|
|
MODULE_LICENSE("GPL");
|
|
#endif /* end of #ifdef CONFIG_MICROP_COMMON*/
|
|
|