Commit 8913c2c1 authored by Christian Marangi's avatar Christian Marangi Committed by Lee Jones
Browse files

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: default avatarLee Jones <lee@kernel.org>
Signed-off-by: default avatarChristian Marangi <ansuelsmth@gmail.com>
Link: https://lore.kernel.org/r/20240626160027.19703-17-ansuelsmth@gmail.com


Signed-off-by: default avatarLee Jones <lee@kernel.org>
parent 082a4d3f
Loading
Loading
Loading
Loading
+3 −116
Original line number Diff line number Diff line
@@ -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);
+109 −0
Original line number Diff line number Diff line
@@ -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,
+19 −13
Original line number Diff line number Diff line
@@ -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)			\
{									\
	return show_engine_leds(dev, attr, buf, nr);			\
}

#define store_leds(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 store_engine_leds(dev, attr, buf, len, nr);	\
}
	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 */