summaryrefslogtreecommitdiff
path: root/drivers/leds
diff options
context:
space:
mode:
authorChristian Marangi <ansuelsmth@gmail.com>2024-06-26 18:00:21 +0200
committerLee Jones <lee@kernel.org>2024-06-26 17:08:31 +0100
commit8913c2c14728851f110e0d439d5bb2360c767cd2 (patch)
treef8a4d5f28eff08bcc5d629f729ad7d6d7e4451e4 /drivers/leds
parent082a4d3f068734eb242e38892d0977ef271c0143 (diff)
downloadlwn-8913c2c14728851f110e0d439d5bb2360c767cd2.tar.gz
lwn-8913c2c14728851f110e0d439d5bb2360c767cd2.zip
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>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/leds-lp5523.c119
-rw-r--r--drivers/leds/leds-lp55xx-common.c109
-rw-r--r--drivers/leds/leds-lp55xx-common.h32
3 files changed, 131 insertions, 129 deletions
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 19b119a2b256..9d91c2c5a3eb 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -225,119 +225,6 @@ out:
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 @@ leave:
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);
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
index 0974488780c0..f0b673c61396 100644
--- a/drivers/leds/leds-lp55xx-common.c
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -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,
diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h
index 5b3e9473cadc..5f2394a6de15 100644
--- a/drivers/leds/leds-lp55xx-common.h
+++ b/drivers/leds/leds-lp55xx-common.h
@@ -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 */