Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358612
b: refs/heads/master
c: 10c06d1
h: refs/heads/master
v: v3
  • Loading branch information
Milo(Woogyom) Kim authored and Bryan Wu committed Feb 6, 2013
1 parent f75accf commit a1b1a1e
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b3b6f8119d752c969c6394314dc7ab80e6611111
refs/heads/master: 10c06d178df11b0b2b746321a80ea14241997127
1 change: 1 addition & 0 deletions trunk/drivers/leds/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ config LEDS_LP3944
config LEDS_LP55XX_COMMON
tristate "Common Driver for TI/National LP5521 and LP5523/55231"
depends on LEDS_LP5521 || LEDS_LP5523
select FW_LOADER
help
This option supports common operations for LP5521 and LP5523/55231
devices.
Expand Down
117 changes: 117 additions & 0 deletions trunk/drivers/leds/leds-lp55xx-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/

#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/module.h>
Expand Down Expand Up @@ -197,7 +198,123 @@ static int lp55xx_init_led(struct lp55xx_led *led,
return 0;
}

static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
{
struct lp55xx_chip *chip = context;
struct device *dev = &chip->cl->dev;

if (!fw) {
dev_err(dev, "firmware request failed\n");
goto out;
}

/* handling firmware data is chip dependent */
mutex_lock(&chip->lock);

chip->fw = fw;
if (chip->cfg->firmware_cb)
chip->cfg->firmware_cb(chip);

mutex_unlock(&chip->lock);

out:
/* firmware should be released for other channel use */
release_firmware(chip->fw);
}

static int lp55xx_request_firmware(struct lp55xx_chip *chip)
{
const char *name = chip->cl->name;
struct device *dev = &chip->cl->dev;

return request_firmware_nowait(THIS_MODULE, true, name, dev,
GFP_KERNEL, chip, lp55xx_firmware_loaded);
}

static ssize_t lp55xx_show_engine_select(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;

return sprintf(buf, "%d\n", chip->engine_idx);
}

static ssize_t lp55xx_store_engine_select(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;
unsigned long val;
int ret;

if (kstrtoul(buf, 0, &val))
return -EINVAL;

/* select the engine to be run */

switch (val) {
case LP55XX_ENGINE_1:
case LP55XX_ENGINE_2:
case LP55XX_ENGINE_3:
mutex_lock(&chip->lock);
chip->engine_idx = val;
ret = lp55xx_request_firmware(chip);
mutex_unlock(&chip->lock);
break;
default:
dev_err(dev, "%lu: invalid engine index. (1, 2, 3)\n", val);
return -EINVAL;
}

if (ret) {
dev_err(dev, "request firmware err: %d\n", ret);
return ret;
}

return len;
}

static inline void lp55xx_run_engine(struct lp55xx_chip *chip, bool start)
{
if (chip->cfg->run_engine)
chip->cfg->run_engine(chip, start);
}

static ssize_t lp55xx_store_engine_run(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
struct lp55xx_chip *chip = led->chip;
unsigned long val;

if (kstrtoul(buf, 0, &val))
return -EINVAL;

/* run or stop the selected engine */

if (val <= 0) {
lp55xx_run_engine(chip, false);
return len;
}

mutex_lock(&chip->lock);
lp55xx_run_engine(chip, true);
mutex_unlock(&chip->lock);

return len;
}

static DEVICE_ATTR(select_engine, S_IRUGO | S_IWUSR,
lp55xx_show_engine_select, lp55xx_store_engine_select);
static DEVICE_ATTR(run_engine, S_IWUSR, NULL, lp55xx_store_engine_run);

static struct attribute *lp55xx_engine_attributes[] = {
&dev_attr_select_engine.attr,
&dev_attr_run_engine.attr,
NULL,
};

Expand Down
19 changes: 19 additions & 0 deletions trunk/drivers/leds/leds-lp55xx-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
#ifndef _LEDS_LP55XX_COMMON_H
#define _LEDS_LP55XX_COMMON_H

enum lp55xx_engine_index {
LP55XX_ENGINE_INVALID,
LP55XX_ENGINE_1,
LP55XX_ENGINE_2,
LP55XX_ENGINE_3,
};

struct lp55xx_led;
struct lp55xx_chip;

Expand All @@ -36,6 +43,8 @@ struct lp55xx_reg {
* @post_init_device : Chip specific initialization code
* @brightness_work_fn : Brightness work function
* @set_led_current : LED current set function
* @firmware_cb : Call function when the firmware is loaded
* @run_engine : Run internal engine for pattern
*/
struct lp55xx_device_config {
const struct lp55xx_reg reset;
Expand All @@ -50,6 +59,12 @@ struct lp55xx_device_config {

/* current setting function */
void (*set_led_current) (struct lp55xx_led *led, u8 led_current);

/* access program memory when the firmware is loaded */
void (*firmware_cb)(struct lp55xx_chip *chip);

/* used for running firmware LED patterns */
void (*run_engine) (struct lp55xx_chip *chip, bool start);
};

/*
Expand All @@ -59,13 +74,17 @@ struct lp55xx_device_config {
* @lock : Lock for user-space interface
* @num_leds : Number of registered LEDs
* @cfg : Device specific configuration data
* @engine_idx : Selected engine number
* @fw : Firmware data for running a LED pattern
*/
struct lp55xx_chip {
struct i2c_client *cl;
struct lp55xx_platform_data *pdata;
struct mutex lock; /* lock for user-space interface */
int num_leds;
struct lp55xx_device_config *cfg;
enum lp55xx_engine_index engine_idx;
const struct firmware *fw;
};

/*
Expand Down

0 comments on commit a1b1a1e

Please sign in to comment.