/* Audio gain in CONFIG2 register */ #define IS31FL3196_AUDIO_GAIN_DB_MAX ((u32)21) #define IS31FL3196_AUDIO_GAIN_DB_STEP 3
/* * regmap is used as a cache of chip's register space, * to avoid reading back brightness values from chip, * which is known to hang.
*/ struct is31fl319x_chip { conststruct is31fl319x_chipdef *cdef; struct i2c_client *client; struct gpio_desc *shutdown_gpio; struct regmap *regmap; struct mutex lock;
u32 audio_gain_db;
/* update PWM register */
ret = regmap_write(is31->regmap, IS31FL3190_PWM(chan), brightness); if (ret < 0) goto out;
/* read current brightness of all PWM channels */ for (i = 0; i < is31->cdef->num_leds; i++) { unsignedint pwm_value; bool on;
/* * since neither cdev nor the chip can provide * the current setting, we read from the regmap cache
*/
ret = regmap_read(is31->regmap, IS31FL3190_PWM(i), &pwm_value);
on = ret >= 0 && pwm_value > LED_OFF;
ctrl |= on << i;
}
if (ctrl > 0) {
dev_dbg(&is31->client->dev, "power up %02x\n", ctrl);
regmap_write(is31->regmap, IS31FL3190_LEDCONTROL, ctrl); /* update PWMs */
regmap_write(is31->regmap, IS31FL3190_DATA_UPDATE, 0x00); /* enable chip from shut down and enable all channels */
ret = regmap_write(is31->regmap, IS31FL319X_SHUTDOWN, 0x20);
} else {
dev_dbg(&is31->client->dev, "power down\n"); /* shut down (no need to clear LEDCONTROL) */
ret = regmap_write(is31->regmap, IS31FL319X_SHUTDOWN, 0x01);
}
out:
mutex_unlock(&is31->lock);
return ret;
}
staticint is31fl3196_brightness_set(struct led_classdev *cdev, enum led_brightness brightness)
{ struct is31fl319x_led *led = container_of(cdev, struct is31fl319x_led, cdev); struct is31fl319x_chip *is31 = led->chip; int chan = led - is31->leds; int ret; int i;
u8 ctrl1 = 0, ctrl2 = 0;
/* update PWM register */
ret = regmap_write(is31->regmap, IS31FL3196_PWM(chan), brightness); if (ret < 0) goto out;
/* read current brightness of all PWM channels */ for (i = 0; i < is31->cdef->num_leds; i++) { unsignedint pwm_value; bool on;
/* * since neither cdev nor the chip can provide * the current setting, we read from the regmap cache
*/
ret = regmap_read(is31->regmap, IS31FL3196_PWM(i), &pwm_value);
on = ret >= 0 && pwm_value > LED_OFF;
if (i < 3)
ctrl1 |= on << i; /* 0..2 => bit 0..2 */ elseif (i < 6)
ctrl1 |= on << (i + 1); /* 3..5 => bit 4..6 */ else
ctrl2 |= on << (i - 6); /* 6..8 => bit 0..2 */
}
if (ctrl1 > 0 || ctrl2 > 0) {
dev_dbg(&is31->client->dev, "power up %02x %02x\n",
ctrl1, ctrl2);
regmap_write(is31->regmap, IS31FL3196_CTRL1, ctrl1);
regmap_write(is31->regmap, IS31FL3196_CTRL2, ctrl2); /* update PWMs */
regmap_write(is31->regmap, IS31FL3196_DATA_UPDATE, 0x00); /* enable chip from shut down */
ret = regmap_write(is31->regmap, IS31FL319X_SHUTDOWN, 0x01);
} else {
dev_dbg(&is31->client->dev, "power down\n"); /* shut down (no need to clear CTRL1/2) */
ret = regmap_write(is31->regmap, IS31FL319X_SHUTDOWN, 0x00);
}
if (fwnode_property_read_string(child, "label", &cdev->name))
cdev->name = fwnode_get_name(child);
ret = fwnode_property_read_string(child, "linux,default-trigger", &cdev->default_trigger); if (ret < 0 && ret != -EINVAL) /* is optional */ return ret;
led->max_microamp = is31->cdef->current_default;
ret = fwnode_property_read_u32(child, "led-max-microamp", &led->max_microamp); if (!ret) { if (led->max_microamp < is31->cdef->current_min) return -EINVAL; /* not supported */
led->max_microamp = min(led->max_microamp,
is31->cdef->current_max);
}
return 0;
}
staticint is31fl319x_parse_fw(struct device *dev, struct is31fl319x_chip *is31)
{ struct fwnode_handle *fwnode = dev_fwnode(dev); int count; int ret;
is31->shutdown_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); if (IS_ERR(is31->shutdown_gpio)) return dev_err_probe(dev, PTR_ERR(is31->shutdown_gpio), "Failed to get shutdown gpio\n");
dev_dbg(dev, "probing with %d leds defined in DT\n", count);
if (!count || count > is31->cdef->num_leds) return dev_err_probe(dev, -ENODEV, "Number of leds defined must be between 1 and %u\n",
is31->cdef->num_leds);
staticint is31fl319x_probe(struct i2c_client *client)
{ struct is31fl319x_chip *is31; struct device *dev = &client->dev; int err; int i = 0;
u32 aggregated_led_microamp;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EIO;
is31 = devm_kzalloc(&client->dev, sizeof(*is31), GFP_KERNEL); if (!is31) return -ENOMEM;
mutex_init(&is31->lock);
err = devm_add_action_or_reset(dev, is31f1319x_mutex_destroy, &is31->lock); if (err) return err;
err = is31fl319x_parse_fw(&client->dev, is31); if (err) return err;
if (is31->shutdown_gpio) {
gpiod_direction_output(is31->shutdown_gpio, 0);
mdelay(5);
gpiod_direction_output(is31->shutdown_gpio, 1);
}
is31->client = client;
is31->regmap = devm_regmap_init_i2c(client, is31->cdef->is31fl319x_regmap_config); if (IS_ERR(is31->regmap)) return dev_err_probe(dev, PTR_ERR(is31->regmap), "failed to allocate register map\n");
i2c_set_clientdata(client, is31);
/* check for write-reply from chip (we can't read any registers) */
err = regmap_write(is31->regmap, is31->cdef->reset_reg, 0x00); if (err < 0) return dev_err_probe(dev, err, "no response from chip write\n");
/* * Kernel conventions require per-LED led-max-microamp property. * But the chip does not allow to limit individual LEDs. * So we take minimum from all subnodes for safety of hardware.
*/
aggregated_led_microamp = is31->cdef->current_max; for (i = 0; i < is31->cdef->num_leds; i++) if (is31->leds[i].configured &&
is31->leds[i].max_microamp < aggregated_led_microamp)
aggregated_led_microamp = is31->leds[i].max_microamp;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.