mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
leds: leds-lp55xx: Generalize sysfs engine_leds
Generalize sysfs engine_leds since their implementation is the same across some lp55xx based LED driver. While at it simplify the implementation for show_engine_leds. Suggested-by: Lee Jones <lee@kernel.org> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> Link: https://lore.kernel.org/r/20240626160027.19703-17-ansuelsmth@gmail.com Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
parent
082a4d3f06
commit
8913c2c147
|
|
@ -225,119 +225,6 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
|
||||
{
|
||||
u16 tmp_mux = 0;
|
||||
int i;
|
||||
|
||||
len = min_t(int, len, LP5523_MAX_LEDS);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
switch (buf[i]) {
|
||||
case '1':
|
||||
tmp_mux |= (1 << i);
|
||||
break;
|
||||
case '0':
|
||||
break;
|
||||
case '\n':
|
||||
i = len;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*mux = tmp_mux;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lp5523_mux_to_array(u16 led_mux, char *array)
|
||||
{
|
||||
int i, pos = 0;
|
||||
|
||||
for (i = 0; i < LP5523_MAX_LEDS; i++)
|
||||
pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
|
||||
|
||||
array[pos] = '\0';
|
||||
}
|
||||
|
||||
static ssize_t show_engine_leds(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf, int nr)
|
||||
{
|
||||
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct lp55xx_chip *chip = led->chip;
|
||||
char mux[LP5523_MAX_LEDS + 1];
|
||||
|
||||
lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
|
||||
|
||||
return sprintf(buf, "%s\n", mux);
|
||||
}
|
||||
show_leds(1)
|
||||
show_leds(2)
|
||||
show_leds(3)
|
||||
|
||||
static int lp5523_load_mux(struct lp55xx_chip *chip, u16 mux, int nr)
|
||||
{
|
||||
struct lp55xx_engine *engine = &chip->engines[nr - 1];
|
||||
int ret;
|
||||
static const u8 mux_page[] = {
|
||||
[LP55XX_ENGINE_1] = LP5523_PAGE_MUX1,
|
||||
[LP55XX_ENGINE_2] = LP5523_PAGE_MUX2,
|
||||
[LP55XX_ENGINE_3] = LP5523_PAGE_MUX3,
|
||||
};
|
||||
|
||||
lp55xx_load_engine(chip);
|
||||
|
||||
ret = lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, mux_page[nr]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = lp55xx_write(chip, LP5523_REG_PROG_MEM, (u8)(mux >> 8));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + 1, (u8)(mux));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
engine->led_mux = mux;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_engine_leds(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len, int nr)
|
||||
{
|
||||
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct lp55xx_chip *chip = led->chip;
|
||||
struct lp55xx_engine *engine = &chip->engines[nr - 1];
|
||||
u16 mux = 0;
|
||||
ssize_t ret;
|
||||
|
||||
if (lp5523_mux_parse(buf, &mux, len))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
chip->engine_idx = nr;
|
||||
ret = -EINVAL;
|
||||
|
||||
if (engine->mode != LP55XX_ENGINE_LOAD)
|
||||
goto leave;
|
||||
|
||||
if (lp5523_load_mux(chip, mux, nr))
|
||||
goto leave;
|
||||
|
||||
ret = len;
|
||||
leave:
|
||||
mutex_unlock(&chip->lock);
|
||||
return ret;
|
||||
}
|
||||
store_leds(1)
|
||||
store_leds(2)
|
||||
store_leds(3)
|
||||
|
||||
static ssize_t lp5523_selftest(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
|
@ -562,9 +449,9 @@ static ssize_t store_master_fader_leds(struct device *dev,
|
|||
LP55XX_DEV_ATTR_ENGINE_MODE(1);
|
||||
LP55XX_DEV_ATTR_ENGINE_MODE(2);
|
||||
LP55XX_DEV_ATTR_ENGINE_MODE(3);
|
||||
static LP55XX_DEV_ATTR_RW(engine1_leds, show_engine1_leds, store_engine1_leds);
|
||||
static LP55XX_DEV_ATTR_RW(engine2_leds, show_engine2_leds, store_engine2_leds);
|
||||
static LP55XX_DEV_ATTR_RW(engine3_leds, show_engine3_leds, store_engine3_leds);
|
||||
LP55XX_DEV_ATTR_ENGINE_LEDS(1);
|
||||
LP55XX_DEV_ATTR_ENGINE_LEDS(2);
|
||||
LP55XX_DEV_ATTR_ENGINE_LEDS(3);
|
||||
LP55XX_DEV_ATTR_ENGINE_LOAD(1);
|
||||
LP55XX_DEV_ATTR_ENGINE_LOAD(2);
|
||||
LP55XX_DEV_ATTR_ENGINE_LOAD(3);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@
|
|||
/* If supported, each ENGINE have an equal amount of pages offset from page 0 */
|
||||
#define LP55xx_PAGE_OFFSET(n, pages) (((n) - 1) * (pages))
|
||||
|
||||
#define LED_ACTIVE(mux, led) (!!((mux) & (0x0001 << (led))))
|
||||
|
||||
/* External clock rate */
|
||||
#define LP55XX_CLK_32K 32768
|
||||
|
||||
|
|
@ -691,6 +693,113 @@ ssize_t lp55xx_store_engine_load(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(lp55xx_store_engine_load);
|
||||
|
||||
static int lp55xx_mux_parse(struct lp55xx_chip *chip, const char *buf,
|
||||
u16 *mux, size_t len)
|
||||
{
|
||||
const struct lp55xx_device_config *cfg = chip->cfg;
|
||||
u16 tmp_mux = 0;
|
||||
int i;
|
||||
|
||||
len = min_t(int, len, cfg->max_channel);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
switch (buf[i]) {
|
||||
case '1':
|
||||
tmp_mux |= (1 << i);
|
||||
break;
|
||||
case '0':
|
||||
break;
|
||||
case '\n':
|
||||
i = len;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*mux = tmp_mux;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t lp55xx_show_engine_leds(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf, int nr)
|
||||
{
|
||||
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct lp55xx_chip *chip = led->chip;
|
||||
const struct lp55xx_device_config *cfg = chip->cfg;
|
||||
unsigned int led_active;
|
||||
int i, pos = 0;
|
||||
|
||||
for (i = 0; i < cfg->max_channel; i++) {
|
||||
led_active = LED_ACTIVE(chip->engines[nr - 1].led_mux, i);
|
||||
pos += sysfs_emit_at(buf, pos, "%x", led_active);
|
||||
}
|
||||
|
||||
pos += sysfs_emit_at(buf, pos, "\n");
|
||||
|
||||
return pos;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lp55xx_show_engine_leds);
|
||||
|
||||
static int lp55xx_load_mux(struct lp55xx_chip *chip, u16 mux, int nr)
|
||||
{
|
||||
struct lp55xx_engine *engine = &chip->engines[nr - 1];
|
||||
const struct lp55xx_device_config *cfg = chip->cfg;
|
||||
u8 mux_page;
|
||||
int ret;
|
||||
|
||||
lp55xx_load_engine(chip);
|
||||
|
||||
/* Derive the MUX page offset by starting at the end of the ENGINE pages */
|
||||
mux_page = cfg->pages_per_engine * LP55XX_ENGINE_MAX + (nr - 1);
|
||||
ret = lp55xx_write(chip, LP55xx_REG_PROG_PAGE_SEL, mux_page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = lp55xx_write(chip, cfg->prog_mem_base.addr, (u8)(mux >> 8));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = lp55xx_write(chip, cfg->prog_mem_base.addr + 1, (u8)(mux));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
engine->led_mux = mux;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t lp55xx_store_engine_leds(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len, int nr)
|
||||
{
|
||||
struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct lp55xx_chip *chip = led->chip;
|
||||
struct lp55xx_engine *engine = &chip->engines[nr - 1];
|
||||
u16 mux = 0;
|
||||
ssize_t ret;
|
||||
|
||||
if (lp55xx_mux_parse(chip, buf, &mux, len))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
chip->engine_idx = nr;
|
||||
ret = -EINVAL;
|
||||
|
||||
if (engine->mode != LP55XX_ENGINE_LOAD)
|
||||
goto leave;
|
||||
|
||||
if (lp55xx_load_mux(chip, mux, nr))
|
||||
goto leave;
|
||||
|
||||
ret = len;
|
||||
leave:
|
||||
mutex_unlock(&chip->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lp55xx_store_engine_leds);
|
||||
|
||||
static struct attribute *lp55xx_engine_attributes[] = {
|
||||
&dev_attr_select_engine.attr,
|
||||
&dev_attr_run_engine.attr,
|
||||
|
|
|
|||
|
|
@ -51,21 +51,21 @@ static ssize_t store_engine##nr##_mode(struct device *dev, \
|
|||
static LP55XX_DEV_ATTR_RW(engine##nr##_mode, show_engine##nr##_mode, \
|
||||
store_engine##nr##_mode)
|
||||
|
||||
#define show_leds(nr) \
|
||||
#define LP55XX_DEV_ATTR_ENGINE_LEDS(nr) \
|
||||
static ssize_t show_engine##nr##_leds(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_engine_leds(dev, attr, buf, nr); \
|
||||
}
|
||||
|
||||
#define store_leds(nr) \
|
||||
static ssize_t store_engine##nr##_leds(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t len) \
|
||||
{ \
|
||||
return store_engine_leds(dev, attr, buf, len, nr); \
|
||||
}
|
||||
return lp55xx_show_engine_leds(dev, attr, buf, nr); \
|
||||
} \
|
||||
static ssize_t store_engine##nr##_leds(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t len) \
|
||||
{ \
|
||||
return lp55xx_store_engine_leds(dev, attr, buf, len, nr); \
|
||||
} \
|
||||
static LP55XX_DEV_ATTR_RW(engine##nr##_leds, show_engine##nr##_leds, \
|
||||
store_engine##nr##_leds)
|
||||
|
||||
#define LP55XX_DEV_ATTR_ENGINE_LOAD(nr) \
|
||||
static ssize_t store_engine##nr##_load(struct device *dev, \
|
||||
|
|
@ -238,5 +238,11 @@ extern ssize_t lp55xx_store_engine_mode(struct device *dev,
|
|||
extern ssize_t lp55xx_store_engine_load(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len, int nr);
|
||||
extern ssize_t lp55xx_show_engine_leds(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf, int nr);
|
||||
extern ssize_t lp55xx_store_engine_leds(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len, int nr);
|
||||
|
||||
#endif /* _LEDS_LP55XX_COMMON_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user