^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2015-16 Golden Delicious Computers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Nikolaus Schaller <hns@goldelico.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * LED driver for the IS31FL319{0,1,3,6,9} to drive 1, 3, 6 or 9 light
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * effect LEDs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* register numbers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define IS31FL319X_SHUTDOWN 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define IS31FL319X_CTRL1 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define IS31FL319X_CTRL2 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define IS31FL319X_CONFIG1 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define IS31FL319X_CONFIG2 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define IS31FL319X_RAMP_MODE 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define IS31FL319X_BREATH_MASK 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define IS31FL319X_PWM(channel) (0x07 + channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define IS31FL319X_DATA_UPDATE 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define IS31FL319X_T0(channel) (0x11 + channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define IS31FL319X_T123_1 0x1a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define IS31FL319X_T123_2 0x1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define IS31FL319X_T123_3 0x1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define IS31FL319X_T4(channel) (0x1d + channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define IS31FL319X_TIME_UPDATE 0x26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define IS31FL319X_RESET 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define IS31FL319X_REG_CNT (IS31FL319X_RESET + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define IS31FL319X_MAX_LEDS 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* CS (Current Setting) in CONFIG2 register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define IS31FL319X_CONFIG2_CS_SHIFT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define IS31FL319X_CONFIG2_CS_MASK 0x7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define IS31FL319X_CONFIG2_CS_STEP_REF 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define IS31FL319X_CURRENT_MIN ((u32)5000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define IS31FL319X_CURRENT_MAX ((u32)40000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define IS31FL319X_CURRENT_STEP ((u32)5000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define IS31FL319X_CURRENT_DEFAULT ((u32)20000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* Audio gain in CONFIG2 register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define IS31FL319X_AUDIO_GAIN_DB_MAX ((u32)21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define IS31FL319X_AUDIO_GAIN_DB_STEP ((u32)3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * regmap is used as a cache of chip's register space,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * to avoid reading back brightness values from chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * which is known to hang.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct is31fl319x_chip {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) const struct is31fl319x_chipdef *cdef;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct gpio_desc *shutdown_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u32 audio_gain_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct is31fl319x_led {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct is31fl319x_chip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct led_classdev cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u32 max_microamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) bool configured;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) } leds[IS31FL319X_MAX_LEDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct is31fl319x_chipdef {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int num_leds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static const struct is31fl319x_chipdef is31fl3190_cdef = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .num_leds = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static const struct is31fl319x_chipdef is31fl3193_cdef = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .num_leds = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static const struct is31fl319x_chipdef is31fl3196_cdef = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .num_leds = 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static const struct is31fl319x_chipdef is31fl3199_cdef = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .num_leds = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static const struct of_device_id of_is31fl319x_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) { .compatible = "issi,is31fl3190", .data = &is31fl3190_cdef, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) { .compatible = "issi,is31fl3191", .data = &is31fl3190_cdef, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) { .compatible = "issi,is31fl3193", .data = &is31fl3193_cdef, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) { .compatible = "issi,is31fl3196", .data = &is31fl3196_cdef, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) { .compatible = "issi,is31fl3199", .data = &is31fl3199_cdef, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) { .compatible = "si-en,sn3199", .data = &is31fl3199_cdef, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) MODULE_DEVICE_TABLE(of, of_is31fl319x_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int is31fl319x_brightness_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct is31fl319x_led *led = container_of(cdev, struct is31fl319x_led,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct is31fl319x_chip *is31 = led->chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int chan = led - is31->leds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u8 ctrl1 = 0, ctrl2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_dbg(&is31->client->dev, "%s %d: %d\n", __func__, chan, brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) mutex_lock(&is31->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* update PWM register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ret = regmap_write(is31->regmap, IS31FL319X_PWM(chan), brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* read current brightness of all PWM channels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) for (i = 0; i < is31->cdef->num_leds; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unsigned int pwm_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) bool on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * since neither cdev nor the chip can provide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * the current setting, we read from the regmap cache
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = regmap_read(is31->regmap, IS31FL319X_PWM(i), &pwm_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dev_dbg(&is31->client->dev, "%s read %d: ret=%d: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) __func__, i, ret, pwm_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) on = ret >= 0 && pwm_value > LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (i < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ctrl1 |= on << i; /* 0..2 => bit 0..2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) else if (i < 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) ctrl1 |= on << (i + 1); /* 3..5 => bit 4..6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ctrl2 |= on << (i - 6); /* 6..8 => bit 0..2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (ctrl1 > 0 || ctrl2 > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) dev_dbg(&is31->client->dev, "power up %02x %02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ctrl1, ctrl2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) regmap_write(is31->regmap, IS31FL319X_CTRL1, ctrl1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) regmap_write(is31->regmap, IS31FL319X_CTRL2, ctrl2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* update PWMs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) regmap_write(is31->regmap, IS31FL319X_DATA_UPDATE, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* enable chip from shut down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ret = regmap_write(is31->regmap, IS31FL319X_SHUTDOWN, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) dev_dbg(&is31->client->dev, "power down\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* shut down (no need to clear CTRL1/2) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ret = regmap_write(is31->regmap, IS31FL319X_SHUTDOWN, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) mutex_unlock(&is31->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int is31fl319x_parse_child_dt(const struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) const struct device_node *child,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct is31fl319x_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct led_classdev *cdev = &led->cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (of_property_read_string(child, "label", &cdev->name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) cdev->name = child->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ret = of_property_read_string(child, "linux,default-trigger",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) &cdev->default_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (ret < 0 && ret != -EINVAL) /* is optional */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) led->max_microamp = IS31FL319X_CURRENT_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ret = of_property_read_u32(child, "led-max-microamp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) &led->max_microamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (led->max_microamp < IS31FL319X_CURRENT_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return -EINVAL; /* not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) led->max_microamp = min(led->max_microamp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) IS31FL319X_CURRENT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static int is31fl319x_parse_dt(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct is31fl319x_chip *is31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct device_node *np = dev_of_node(dev), *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) is31->shutdown_gpio = devm_gpiod_get_optional(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) "shutdown",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) GPIOD_OUT_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (IS_ERR(is31->shutdown_gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) ret = PTR_ERR(is31->shutdown_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) dev_err(dev, "Failed to get shutdown gpio: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) is31->cdef = device_get_match_data(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) count = of_get_available_child_count(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) dev_dbg(dev, "probing with %d leds defined in DT\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!count || count > is31->cdef->num_leds) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) dev_err(dev, "Number of leds defined must be between 1 and %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) is31->cdef->num_leds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) for_each_available_child_of_node(np, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct is31fl319x_led *led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) ret = of_property_read_u32(child, "reg", ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dev_err(dev, "Failed to read led 'reg' property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (reg < 1 || reg > is31->cdef->num_leds) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) dev_err(dev, "invalid led reg %u\n", reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) led = &is31->leds[reg - 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (led->configured) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_err(dev, "led %u is already configured\n", reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) ret = is31fl319x_parse_child_dt(dev, child, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) dev_err(dev, "led %u DT parsing failed\n", reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) led->configured = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) is31->audio_gain_db = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) ret = of_property_read_u32(np, "audio-gain-db", &is31->audio_gain_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) is31->audio_gain_db = min(is31->audio_gain_db,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) IS31FL319X_AUDIO_GAIN_DB_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) put_child_node:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) of_node_put(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static bool is31fl319x_readable_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) { /* we have no readable registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static bool is31fl319x_volatile_reg(struct device *dev, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) { /* volatile registers are not cached */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) case IS31FL319X_DATA_UPDATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) case IS31FL319X_TIME_UPDATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) case IS31FL319X_RESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return true; /* always write-through */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static const struct reg_default is31fl319x_reg_defaults[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) { IS31FL319X_CONFIG1, 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) { IS31FL319X_CONFIG2, 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) { IS31FL319X_PWM(0), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) { IS31FL319X_PWM(1), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) { IS31FL319X_PWM(2), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) { IS31FL319X_PWM(3), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) { IS31FL319X_PWM(4), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) { IS31FL319X_PWM(5), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) { IS31FL319X_PWM(6), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) { IS31FL319X_PWM(7), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) { IS31FL319X_PWM(8), 0x00},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static struct regmap_config regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .reg_bits = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .val_bits = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .max_register = IS31FL319X_REG_CNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .cache_type = REGCACHE_FLAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .readable_reg = is31fl319x_readable_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .volatile_reg = is31fl319x_volatile_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .reg_defaults = is31fl319x_reg_defaults,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .num_reg_defaults = ARRAY_SIZE(is31fl319x_reg_defaults),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static inline int is31fl319x_microamp_to_cs(struct device *dev, u32 microamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) { /* round down to nearest supported value (range check done by caller) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) u32 step = microamp / IS31FL319X_CURRENT_STEP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return ((IS31FL319X_CONFIG2_CS_STEP_REF - step) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) IS31FL319X_CONFIG2_CS_MASK) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) IS31FL319X_CONFIG2_CS_SHIFT; /* CS encoding */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static inline int is31fl319x_db_to_gain(u32 dezibel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) { /* round down to nearest supported value (range check done by caller) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return dezibel / IS31FL319X_AUDIO_GAIN_DB_STEP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static int is31fl319x_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct is31fl319x_chip *is31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct device *dev = &client->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) u32 aggregated_led_microamp = IS31FL319X_CURRENT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) is31 = devm_kzalloc(&client->dev, sizeof(*is31), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (!is31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) mutex_init(&is31->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) err = is31fl319x_parse_dt(&client->dev, is31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) goto free_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (is31->shutdown_gpio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) gpiod_direction_output(is31->shutdown_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) mdelay(5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) gpiod_direction_output(is31->shutdown_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) is31->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) is31->regmap = devm_regmap_init_i2c(client, ®map_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (IS_ERR(is31->regmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) dev_err(&client->dev, "failed to allocate register map\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) err = PTR_ERR(is31->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) goto free_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) i2c_set_clientdata(client, is31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* check for write-reply from chip (we can't read any registers) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) err = regmap_write(is31->regmap, IS31FL319X_RESET, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) dev_err(&client->dev, "no response from chip write: err = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) err = -EIO; /* does not answer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) goto free_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * Kernel conventions require per-LED led-max-microamp property.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * But the chip does not allow to limit individual LEDs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * So we take minimum from all subnodes for safety of hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) for (i = 0; i < is31->cdef->num_leds; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (is31->leds[i].configured &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) is31->leds[i].max_microamp < aggregated_led_microamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) aggregated_led_microamp = is31->leds[i].max_microamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) regmap_write(is31->regmap, IS31FL319X_CONFIG2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) is31fl319x_microamp_to_cs(dev, aggregated_led_microamp) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) is31fl319x_db_to_gain(is31->audio_gain_db));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) for (i = 0; i < is31->cdef->num_leds; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct is31fl319x_led *led = &is31->leds[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (!led->configured)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) led->chip = is31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) led->cdev.brightness_set_blocking = is31fl319x_brightness_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) err = devm_led_classdev_register(&client->dev, &led->cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) goto free_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) free_mutex:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) mutex_destroy(&is31->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static int is31fl319x_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct is31fl319x_chip *is31 = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) mutex_destroy(&is31->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * i2c-core (and modalias) requires that id_table be properly filled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * even though it is not used for DeviceTree based instantiation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static const struct i2c_device_id is31fl319x_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) { "is31fl3190" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) { "is31fl3191" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) { "is31fl3193" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) { "is31fl3196" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) { "is31fl3199" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) { "sn3199" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) MODULE_DEVICE_TABLE(i2c, is31fl319x_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static struct i2c_driver is31fl319x_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .name = "leds-is31fl319x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .of_match_table = of_match_ptr(of_is31fl319x_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .probe = is31fl319x_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) .remove = is31fl319x_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) .id_table = is31fl319x_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) module_i2c_driver(is31fl319x_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) MODULE_AUTHOR("Andrey Utkin <andrey_utkin@fastmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) MODULE_DESCRIPTION("IS31FL319X LED driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) MODULE_LICENSE("GPL v2");