summaryrefslogtreecommitdiff
path: root/drivers/leds/leds-is31fl32xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds/leds-is31fl32xx.c')
-rw-r--r--drivers/leds/leds-is31fl32xx.c72
1 files changed, 52 insertions, 20 deletions
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 3b55af9a8c58..dc9349f9d350 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -15,7 +15,6 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
/* Used to indicate a device has no such register */
#define IS31FL32XX_REG_NONE 0xFF
@@ -33,6 +32,8 @@
#define IS31FL3216_CONFIG_SSD_ENABLE BIT(7)
#define IS31FL3216_CONFIG_SSD_DISABLE 0
+#define IS31FL32XX_PWM_FREQUENCY_22KHZ 0x01
+
struct is31fl32xx_priv;
struct is31fl32xx_led_data {
struct led_classdev cdev;
@@ -54,6 +55,7 @@ struct is31fl32xx_priv {
* @pwm_update_reg : address of PWM Update register
* @global_control_reg : address of Global Control register (optional)
* @reset_reg : address of Reset register (optional)
+ * @output_frequency_setting_reg: address of output frequency register (optional)
* @pwm_register_base : address of first PWM register
* @pwm_registers_reversed: : true if PWM registers count down instead of up
* @led_control_register_base : address of first LED control register (optional)
@@ -77,6 +79,7 @@ struct is31fl32xx_chipdef {
u8 pwm_update_reg;
u8 global_control_reg;
u8 reset_reg;
+ u8 output_frequency_setting_reg;
u8 pwm_register_base;
bool pwm_registers_reversed;
u8 led_control_register_base;
@@ -91,6 +94,19 @@ static const struct is31fl32xx_chipdef is31fl3236_cdef = {
.pwm_update_reg = 0x25,
.global_control_reg = 0x4a,
.reset_reg = 0x4f,
+ .output_frequency_setting_reg = IS31FL32XX_REG_NONE,
+ .pwm_register_base = 0x01,
+ .led_control_register_base = 0x26,
+ .enable_bits_per_led_control_register = 1,
+};
+
+static const struct is31fl32xx_chipdef is31fl3236a_cdef = {
+ .channels = 36,
+ .shutdown_reg = 0x00,
+ .pwm_update_reg = 0x25,
+ .global_control_reg = 0x4a,
+ .reset_reg = 0x4f,
+ .output_frequency_setting_reg = 0x4b,
.pwm_register_base = 0x01,
.led_control_register_base = 0x26,
.enable_bits_per_led_control_register = 1,
@@ -102,6 +118,7 @@ static const struct is31fl32xx_chipdef is31fl3235_cdef = {
.pwm_update_reg = 0x25,
.global_control_reg = 0x4a,
.reset_reg = 0x4f,
+ .output_frequency_setting_reg = IS31FL32XX_REG_NONE,
.pwm_register_base = 0x05,
.led_control_register_base = 0x2a,
.enable_bits_per_led_control_register = 1,
@@ -113,6 +130,7 @@ static const struct is31fl32xx_chipdef is31fl3218_cdef = {
.pwm_update_reg = 0x16,
.global_control_reg = IS31FL32XX_REG_NONE,
.reset_reg = 0x17,
+ .output_frequency_setting_reg = IS31FL32XX_REG_NONE,
.pwm_register_base = 0x01,
.led_control_register_base = 0x13,
.enable_bits_per_led_control_register = 6,
@@ -127,6 +145,7 @@ static const struct is31fl32xx_chipdef is31fl3216_cdef = {
.pwm_update_reg = 0xB0,
.global_control_reg = IS31FL32XX_REG_NONE,
.reset_reg = IS31FL32XX_REG_NONE,
+ .output_frequency_setting_reg = IS31FL32XX_REG_NONE,
.pwm_register_base = 0x10,
.pwm_registers_reversed = true,
.led_control_register_base = 0x01,
@@ -364,10 +383,22 @@ static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
static int is31fl32xx_parse_dt(struct device *dev,
struct is31fl32xx_priv *priv)
{
- struct device_node *child;
+ const struct is31fl32xx_chipdef *cdef = priv->cdef;
int ret = 0;
- for_each_available_child_of_node(dev_of_node(dev), child) {
+ if ((cdef->output_frequency_setting_reg != IS31FL32XX_REG_NONE) &&
+ of_property_read_bool(dev_of_node(dev), "issi,22khz-pwm")) {
+
+ ret = is31fl32xx_write(priv, cdef->output_frequency_setting_reg,
+ IS31FL32XX_PWM_FREQUENCY_22KHZ);
+
+ if (ret) {
+ dev_err(dev, "Failed to write output PWM frequency register\n");
+ return ret;
+ }
+ }
+
+ for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
struct led_init_data init_data = {};
struct is31fl32xx_led_data *led_data =
&priv->leds[priv->num_leds];
@@ -377,7 +408,7 @@ static int is31fl32xx_parse_dt(struct device *dev,
ret = is31fl32xx_parse_child_dt(dev, child, led_data);
if (ret)
- goto err;
+ return ret;
/* Detect if channel is already in use by another child */
other_led_data = is31fl32xx_find_led_data(priv,
@@ -386,7 +417,7 @@ static int is31fl32xx_parse_dt(struct device *dev,
dev_err(dev,
"Node %pOF 'reg' conflicts with another LED\n",
child);
- goto err;
+ return -EINVAL;
}
init_data.fwnode = of_fwnode_handle(child);
@@ -396,33 +427,29 @@ static int is31fl32xx_parse_dt(struct device *dev,
if (ret) {
dev_err(dev, "Failed to register LED for %pOF: %d\n",
child, ret);
- goto err;
+ return ret;
}
priv->num_leds++;
}
return 0;
-
-err:
- of_node_put(child);
- return ret;
}
static const struct of_device_id of_is31fl32xx_match[] = {
- { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
- { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
- { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
- { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, },
- { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
- { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, },
+ { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
+ { .compatible = "issi,is31fl3236a", .data = &is31fl3236a_cdef, },
+ { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
+ { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
+ { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, },
+ { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
+ { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, },
{},
};
MODULE_DEVICE_TABLE(of, of_is31fl32xx_match);
-static int is31fl32xx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int is31fl32xx_probe(struct i2c_client *client)
{
const struct is31fl32xx_chipdef *cdef;
struct device *dev = &client->dev;
@@ -456,11 +483,15 @@ static int is31fl32xx_probe(struct i2c_client *client,
return 0;
}
-static int is31fl32xx_remove(struct i2c_client *client)
+static void is31fl32xx_remove(struct i2c_client *client)
{
struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
+ int ret;
- return is31fl32xx_reset_regs(priv);
+ ret = is31fl32xx_reset_regs(priv);
+ if (ret)
+ dev_err(&client->dev, "Failed to reset registers on removal (%pe)\n",
+ ERR_PTR(ret));
}
/*
@@ -469,6 +500,7 @@ static int is31fl32xx_remove(struct i2c_client *client)
*/
static const struct i2c_device_id is31fl32xx_id[] = {
{ "is31fl3236" },
+ { "is31fl3236a" },
{ "is31fl3235" },
{ "is31fl3218" },
{ "sn3218" },