The LP55xx common driver has a device attribute for running selected engine. Then an application can run the engine via the sysfs. Actual operation is accessing the register. Therefore, run_engine internal function should be configured in each driver. Related definitions and internal static functions are added. Signed-off-by: Milo(Woogyom) Kim <milo.kim@xxxxxx> --- drivers/leds/leds-lp5521.c | 86 +++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds-lp5523.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 45a2d56..38157a0 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -101,6 +101,29 @@ /* Reset register value */ #define LP5521_RESET 0xFF +/* Program Memory Operations */ +#define LP5521_MODE_R_M 0x30 /* Operation Mode Register */ +#define LP5521_MODE_G_M 0x0C +#define LP5521_MODE_B_M 0x03 +#define LP5521_LOAD_R 0x10 +#define LP5521_LOAD_G 0x04 +#define LP5521_LOAD_B 0x01 + +#define LP5521_R_IS_LOADING(mode) \ + ((mode & LP5521_MODE_R_M) == LP5521_LOAD_R) +#define LP5521_G_IS_LOADING(mode) \ + ((mode & LP5521_MODE_G_M) == LP5521_LOAD_G) +#define LP5521_B_IS_LOADING(mode) \ + ((mode & LP5521_MODE_B_M) == LP5521_LOAD_B) + +#define LP5521_EXEC_R_M 0x30 /* Enable Register */ +#define LP5521_EXEC_G_M 0x0C +#define LP5521_EXEC_B_M 0x03 +#define LP5521_EXEC_M 0x3F +#define LP5521_RUN_R 0x20 +#define LP5521_RUN_G 0x08 +#define LP5521_RUN_B 0x02 + struct lp5521_engine { int id; u8 mode; @@ -128,6 +151,12 @@ struct lp5521_chip { u8 num_leds; }; +static inline void lp5521_wait_opmode_done(void) +{ + /* operation mode change needs to be longer than 153 us */ + usleep_range(200, 300); +} + static inline void lp5521_wait_enable_done(void) { /* it takes more 488 us to update ENABLE register */ @@ -236,6 +265,62 @@ static void lp5521_set_led_current(struct lp55xx_led *led, u8 led_current) led_current); } +static void lp5521_stop_engine(struct lp55xx_chip *chip) +{ + lp55xx_write(chip, LP5521_REG_OP_MODE, 0); + lp5521_wait_opmode_done(); +} + +static void lp5521_run_engine(struct lp55xx_chip *chip, bool start) +{ + int ret; + u8 mode; + u8 exec; + + /* stop engine */ + if (!start) { + lp5521_stop_engine(chip); + lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); + lp5521_wait_opmode_done(); + return; + } + + /* + * To run the engine, + * operation mode and enable register should updated at the same time + */ + + ret = lp55xx_read(chip, LP5521_REG_OP_MODE, &mode); + if (ret) + return; + + ret = lp55xx_read(chip, LP5521_REG_ENABLE, &exec); + if (ret) + return; + + /* change operation mode to RUN only when each engine is loading */ + if (LP5521_R_IS_LOADING(mode)) { + mode = (mode & ~LP5521_MODE_R_M) | LP5521_RUN_R; + exec = (exec & ~LP5521_EXEC_R_M) | LP5521_RUN_R; + } + + if (LP5521_G_IS_LOADING(mode)) { + mode = (mode & ~LP5521_MODE_G_M) | LP5521_RUN_G; + exec = (exec & ~LP5521_EXEC_G_M) | LP5521_RUN_G; + } + + if (LP5521_B_IS_LOADING(mode)) { + mode = (mode & ~LP5521_MODE_B_M) | LP5521_RUN_B; + exec = (exec & ~LP5521_EXEC_B_M) | LP5521_RUN_B; + } + + lp55xx_write(chip, LP5521_REG_OP_MODE, mode); + lp5521_wait_opmode_done(); + + lp55xx_update_bits(chip, LP5521_REG_ENABLE, LP5521_EXEC_M, exec); + lp5521_wait_enable_done(); +} + static int lp5521_post_init_device(struct lp55xx_chip *chip) { int ret; @@ -618,6 +703,7 @@ static struct lp55xx_device_config lp5521_cfg = { .post_init_device = lp5521_post_init_device, .brightness_work_fn = lp5521_led_brightness_work, .set_led_current = lp5521_set_led_current, + .run_engine = lp5521_run_engine, }; static int __devinit lp5521_probe(struct i2c_client *client, diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index e262fdc..9aa03d2 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -110,6 +110,29 @@ #define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) #define SHIFT_MASK(id) (((id) - 1) * 2) +/* Program Memory Operations */ +#define LP5523_MODE_ENG1_M 0x30 /* Operation Mode Register */ +#define LP5523_MODE_ENG2_M 0x0C +#define LP5523_MODE_ENG3_M 0x03 +#define LP5523_LOAD_ENG1 0x10 +#define LP5523_LOAD_ENG2 0x04 +#define LP5523_LOAD_ENG3 0x01 + +#define LP5523_ENG1_IS_LOADING(mode) \ + ((mode & LP5523_MODE_ENG1_M) == LP5523_LOAD_ENG1) +#define LP5523_ENG2_IS_LOADING(mode) \ + ((mode & LP5523_MODE_ENG2_M) == LP5523_LOAD_ENG2) +#define LP5523_ENG3_IS_LOADING(mode) \ + ((mode & LP5523_MODE_ENG3_M) == LP5523_LOAD_ENG3) + +#define LP5523_EXEC_ENG1_M 0x30 /* Enable Register */ +#define LP5523_EXEC_ENG2_M 0x0C +#define LP5523_EXEC_ENG3_M 0x03 +#define LP5523_EXEC_M 0x3F +#define LP5523_RUN_ENG1 0x20 +#define LP5523_RUN_ENG2 0x08 +#define LP5523_RUN_ENG3 0x02 + enum lp5523_chip_id { LP5523, LP55231, @@ -144,6 +167,11 @@ struct lp5523_chip { u8 num_leds; }; +static inline void lp5523_wait_opmode_done(void) +{ + usleep_range(1000, 2000); +} + static inline struct lp5523_led *cdev_to_led(struct led_classdev *cdev) { return container_of(cdev, struct lp5523_led, cdev); @@ -476,6 +504,68 @@ static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current) led_current); } +static void lp5523_stop_engine(struct lp55xx_chip *chip) +{ + lp55xx_write(chip, LP5523_REG_OP_MODE, 0); + lp5523_wait_opmode_done(); +} + +static void lp5523_turn_off_channels(struct lp55xx_chip *chip) +{ + int i; + + for (i = 0; i < LP5523_MAX_LEDS; i++) + lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0); +} + +static void lp5523_run_engine(struct lp55xx_chip *chip, bool start) +{ + int ret; + u8 mode; + u8 exec; + + /* stop engine */ + if (!start) { + lp5523_stop_engine(chip); + lp5523_turn_off_channels(chip); + return; + } + + /* + * To run the engine, + * operation mode and enable register should updated at the same time + */ + + ret = lp55xx_read(chip, LP5523_REG_OP_MODE, &mode); + if (ret) + return; + + ret = lp55xx_read(chip, LP5523_REG_ENABLE, &exec); + if (ret) + return; + + /* change operation mode to RUN only when each engine is loading */ + if (LP5523_ENG1_IS_LOADING(mode)) { + mode = (mode & ~LP5523_MODE_ENG1_M) | LP5523_RUN_ENG1; + exec = (exec & ~LP5523_EXEC_ENG1_M) | LP5523_RUN_ENG1; + } + + if (LP5523_ENG2_IS_LOADING(mode)) { + mode = (mode & ~LP5523_MODE_ENG2_M) | LP5523_RUN_ENG2; + exec = (exec & ~LP5523_EXEC_ENG2_M) | LP5523_RUN_ENG2; + } + + if (LP5523_ENG3_IS_LOADING(mode)) { + mode = (mode & ~LP5523_MODE_ENG3_M) | LP5523_RUN_ENG3; + exec = (exec & ~LP5523_EXEC_ENG3_M) | LP5523_RUN_ENG3; + } + + lp55xx_write(chip, LP5523_REG_OP_MODE, mode); + lp5523_wait_opmode_done(); + + lp55xx_update_bits(chip, LP5523_REG_ENABLE, LP5523_EXEC_M, exec); +} + static int lp5523_do_store_load(struct lp5523_engine *engine, const char *buf, size_t len) { @@ -700,6 +790,7 @@ static struct lp55xx_device_config lp5523_cfg = { .post_init_device = lp5523_post_init_device, .brightness_work_fn = lp5523_led_brightness_work, .set_led_current = lp5523_set_led_current, + .run_engine = lp5523_run_engine, }; static int __devinit lp5523_probe(struct i2c_client *client, -- 1.7.9.5 Best Regards, Milo -- To unsubscribe from this list: send the line "unsubscribe linux-leds" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html