From 297b60346df8beafee954a0fd7c2d64f33f3b9bc Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 11 May 2024 01:44:05 +0000 Subject: [PATCH] rtl8211F_led_control --- kernel/drivers/leds/leds-lm3692x.c | 240 +++++++++++++++++++++++++++++++++++++---------------------- 1 files changed, 149 insertions(+), 91 deletions(-) diff --git a/kernel/drivers/leds/leds-lm3692x.c b/kernel/drivers/leds/leds-lm3692x.c index d79a66a..55e6443 100644 --- a/kernel/drivers/leds/leds-lm3692x.c +++ b/kernel/drivers/leds/leds-lm3692x.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 // TI LM3692x LED chip family driver -// Copyright (C) 2017-18 Texas Instruments Incorporated - http://www.ti.com/ +// Copyright (C) 2017-18 Texas Instruments Incorporated - https://www.ti.com/ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/leds.h> +#include <linux/log2.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> @@ -13,7 +14,6 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> -#include <uapi/linux/uleds.h> #define LM36922_MODEL 0 #define LM36923_MODEL 1 @@ -103,7 +103,6 @@ * @regmap - Devices register map * @enable_gpio - VDDIO/EN gpio to enable communication interface * @regulator - LED supply regulator pointer - * @label - LED label * @led_enable - LED sync to be enabled * @model_id - Current device model ID enumerated */ @@ -114,9 +113,11 @@ struct regmap *regmap; struct gpio_desc *enable_gpio; struct regulator *regulator; - char label[LED_MAX_NAME_SIZE]; int led_enable; int model_id; + + u8 boost_ctrl, brightness_ctrl; + bool enabled; }; static const struct reg_default lm3692x_reg_defs[] = { @@ -165,48 +166,19 @@ return read_buf; } -static int lm3692x_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brt_val) -{ - struct lm3692x_led *led = - container_of(led_cdev, struct lm3692x_led, led_dev); - int ret; - int led_brightness_lsb = (brt_val >> 5); - - mutex_lock(&led->lock); - - ret = lm3692x_fault_check(led); - if (ret) { - dev_err(&led->client->dev, "Cannot read/clear faults\n"); - goto out; - } - - ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val); - if (ret) { - dev_err(&led->client->dev, "Cannot write MSB\n"); - goto out; - } - - ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb); - if (ret) { - dev_err(&led->client->dev, "Cannot write LSB\n"); - goto out; - } -out: - mutex_unlock(&led->lock); - return ret; -} - -static int lm3692x_init(struct lm3692x_led *led) +static int lm3692x_leds_enable(struct lm3692x_led *led) { int enable_state; - int ret; + int ret, reg_ret; + + if (led->enabled) + return 0; if (led->regulator) { ret = regulator_enable(led->regulator); if (ret) { dev_err(&led->client->dev, - "Failed to enable regulator\n"); + "Failed to enable regulator: %d\n", ret); return ret; } } @@ -216,7 +188,8 @@ ret = lm3692x_fault_check(led); if (ret) { - dev_err(&led->client->dev, "Cannot read/clear faults\n"); + dev_err(&led->client->dev, "Cannot read/clear faults: %d\n", + ret); goto out; } @@ -250,10 +223,7 @@ if (ret) goto out; - ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL, - LM3692X_BRHT_MODE_RAMP_MULTI | - LM3692X_BL_ADJ_POL | - LM3692X_RAMP_RATE_250us); + ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL, led->boost_ctrl); if (ret) goto out; @@ -270,7 +240,7 @@ goto out; ret = regmap_write(led->regmap, LM3692X_BRT_CTRL, - LM3692X_BL_ADJ_POL | LM3692X_PWM_HYSTER_4LSB); + LM3692X_BL_ADJ_POL | LM3692X_RAMP_EN); if (ret) goto out; @@ -306,6 +276,7 @@ ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_ENABLE_MASK, enable_state | LM3692X_DEVICE_EN); + led->enabled = true; return ret; out: dev_err(&led->client->dev, "Fail writing initialization values\n"); @@ -314,18 +285,101 @@ gpiod_direction_output(led->enable_gpio, 0); if (led->regulator) { - ret = regulator_disable(led->regulator); - if (ret) + reg_ret = regulator_disable(led->regulator); + if (reg_ret) dev_err(&led->client->dev, - "Failed to disable regulator\n"); + "Failed to disable regulator: %d\n", reg_ret); } return ret; } + +static int lm3692x_leds_disable(struct lm3692x_led *led) +{ + int ret; + + if (!led->enabled) + return 0; + + ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN, 0); + if (ret) { + dev_err(&led->client->dev, "Failed to disable regulator: %d\n", + ret); + return ret; + } + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator: %d\n", ret); + } + + led->enabled = false; + return ret; +} + +static int lm3692x_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lm3692x_led *led = + container_of(led_cdev, struct lm3692x_led, led_dev); + int ret; + int led_brightness_lsb = (brt_val >> 5); + + mutex_lock(&led->lock); + + if (brt_val == 0) { + ret = lm3692x_leds_disable(led); + goto out; + } else { + lm3692x_leds_enable(led); + } + + ret = lm3692x_fault_check(led); + if (ret) { + dev_err(&led->client->dev, "Cannot read/clear faults: %d\n", + ret); + goto out; + } + + ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val); + if (ret) { + dev_err(&led->client->dev, "Cannot write MSB: %d\n", ret); + goto out; + } + + ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb); + if (ret) { + dev_err(&led->client->dev, "Cannot write LSB: %d\n", ret); + goto out; + } +out: + mutex_unlock(&led->lock); + return ret; +} + +static enum led_brightness lm3692x_max_brightness(struct lm3692x_led *led, + u32 max_cur) +{ + u32 max_code; + + /* see p.12 of LM36922 data sheet for brightness formula */ + max_code = ((max_cur * 1000) - 37806) / 12195; + if (max_code > 0x7FF) + max_code = 0x7FF; + + return max_code >> 3; +} + static int lm3692x_probe_dt(struct lm3692x_led *led) { struct fwnode_handle *child = NULL; - const char *name; + struct led_init_data init_data = {}; + u32 ovp, max_cur; int ret; led->enable_gpio = devm_gpiod_get_optional(&led->client->dev, @@ -340,14 +394,37 @@ led->regulator = devm_regulator_get_optional(&led->client->dev, "vled"); if (IS_ERR(led->regulator)) { ret = PTR_ERR(led->regulator); - if (ret != -ENODEV) { - if (ret != -EPROBE_DEFER) - dev_err(&led->client->dev, - "Failed to get vled regulator: %d\n", - ret); - return ret; - } + if (ret != -ENODEV) + return dev_err_probe(&led->client->dev, ret, + "Failed to get vled regulator\n"); + led->regulator = NULL; + } + + led->boost_ctrl = LM3692X_BOOST_SW_1MHZ | + LM3692X_BOOST_SW_NO_SHIFT | + LM3692X_OCP_PROT_1_5A; + ret = device_property_read_u32(&led->client->dev, + "ti,ovp-microvolt", &ovp); + if (ret) { + led->boost_ctrl |= LM3692X_OVP_29V; + } else { + switch (ovp) { + case 17000000: + break; + case 21000000: + led->boost_ctrl |= LM3692X_OVP_21V; + break; + case 25000000: + led->boost_ctrl |= LM3692X_OVP_25V; + break; + case 29000000: + led->boost_ctrl |= LM3692X_OVP_29V; + break; + default: + dev_err(&led->client->dev, "Invalid OVP %d\n", ovp); + return -EINVAL; + } } child = device_get_next_child_node(&led->client->dev, child); @@ -356,34 +433,28 @@ return -ENODEV; } - fwnode_property_read_string(child, "linux,default-trigger", - &led->led_dev.default_trigger); - - ret = fwnode_property_read_string(child, "label", &name); - if (ret) - snprintf(led->label, sizeof(led->label), - "%s::", led->client->name); - else - snprintf(led->label, sizeof(led->label), - "%s:%s", led->client->name, name); - ret = fwnode_property_read_u32(child, "reg", &led->led_enable); if (ret) { + fwnode_handle_put(child); dev_err(&led->client->dev, "reg DT property missing\n"); return ret; } - led->led_dev.name = led->label; + ret = fwnode_property_read_u32(child, "led-max-microamp", &max_cur); + led->led_dev.max_brightness = ret ? LED_FULL : + lm3692x_max_brightness(led, max_cur); - ret = devm_led_classdev_register(&led->client->dev, &led->led_dev); - if (ret) { + init_data.fwnode = child; + init_data.devicename = led->client->name; + init_data.default_label = ":"; + + ret = devm_led_classdev_register_ext(&led->client->dev, &led->led_dev, + &init_data); + if (ret) dev_err(&led->client->dev, "led register err: %d\n", ret); - return ret; - } - led->led_dev.dev->of_node = to_of_node(child); - - return 0; + fwnode_handle_put(init_data.fwnode); + return ret; } static int lm3692x_probe(struct i2c_client *client, @@ -414,7 +485,7 @@ if (ret) return ret; - ret = lm3692x_init(led); + ret = lm3692x_leds_enable(led); if (ret) return ret; @@ -426,22 +497,9 @@ struct lm3692x_led *led = i2c_get_clientdata(client); int ret; - ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN, 0); - if (ret) { - dev_err(&led->client->dev, "Failed to disable regulator\n"); + ret = lm3692x_leds_disable(led); + if (ret) return ret; - } - - if (led->enable_gpio) - gpiod_direction_output(led->enable_gpio, 0); - - if (led->regulator) { - ret = regulator_disable(led->regulator); - if (ret) - dev_err(&led->client->dev, - "Failed to disable regulator\n"); - } - mutex_destroy(&led->lock); return 0; -- Gitblit v1.6.2