12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
216c5c023SJohan Hovold /*
316c5c023SJohan Hovold * lm3533-core.c -- LM3533 Core
416c5c023SJohan Hovold *
516c5c023SJohan Hovold * Copyright (C) 2011-2012 Texas Instruments
616c5c023SJohan Hovold *
716c5c023SJohan Hovold * Author: Johan Hovold <jhovold@gmail.com>
816c5c023SJohan Hovold */
916c5c023SJohan Hovold
1016c5c023SJohan Hovold #include <linux/module.h>
1116c5c023SJohan Hovold #include <linux/init.h>
1216c5c023SJohan Hovold #include <linux/kernel.h>
1316c5c023SJohan Hovold #include <linux/err.h>
1416c5c023SJohan Hovold #include <linux/gpio.h>
1516c5c023SJohan Hovold #include <linux/i2c.h>
1616c5c023SJohan Hovold #include <linux/mfd/core.h>
1716c5c023SJohan Hovold #include <linux/regmap.h>
1816c5c023SJohan Hovold #include <linux/seq_file.h>
1916c5c023SJohan Hovold #include <linux/slab.h>
2016c5c023SJohan Hovold #include <linux/uaccess.h>
2116c5c023SJohan Hovold
2216c5c023SJohan Hovold #include <linux/mfd/lm3533.h>
2316c5c023SJohan Hovold
2416c5c023SJohan Hovold
2516c5c023SJohan Hovold #define LM3533_BOOST_OVP_MASK 0x06
2616c5c023SJohan Hovold #define LM3533_BOOST_OVP_SHIFT 1
2716c5c023SJohan Hovold
2816c5c023SJohan Hovold #define LM3533_BOOST_FREQ_MASK 0x01
2916c5c023SJohan Hovold #define LM3533_BOOST_FREQ_SHIFT 0
3016c5c023SJohan Hovold
3116c5c023SJohan Hovold #define LM3533_BL_ID_MASK 1
3216c5c023SJohan Hovold #define LM3533_LED_ID_MASK 3
3316c5c023SJohan Hovold #define LM3533_BL_ID_MAX 1
3416c5c023SJohan Hovold #define LM3533_LED_ID_MAX 3
3516c5c023SJohan Hovold
3616c5c023SJohan Hovold #define LM3533_HVLED_ID_MAX 2
3716c5c023SJohan Hovold #define LM3533_LVLED_ID_MAX 5
3816c5c023SJohan Hovold
3916c5c023SJohan Hovold #define LM3533_REG_OUTPUT_CONF1 0x10
4016c5c023SJohan Hovold #define LM3533_REG_OUTPUT_CONF2 0x11
4116c5c023SJohan Hovold #define LM3533_REG_BOOST_PWM 0x2c
4216c5c023SJohan Hovold
4316c5c023SJohan Hovold #define LM3533_REG_MAX 0xb2
4416c5c023SJohan Hovold
4516c5c023SJohan Hovold
4616c5c023SJohan Hovold static struct mfd_cell lm3533_als_devs[] = {
4716c5c023SJohan Hovold {
4816c5c023SJohan Hovold .name = "lm3533-als",
4916c5c023SJohan Hovold .id = -1,
5016c5c023SJohan Hovold },
5116c5c023SJohan Hovold };
5216c5c023SJohan Hovold
5316c5c023SJohan Hovold static struct mfd_cell lm3533_bl_devs[] = {
5416c5c023SJohan Hovold {
5516c5c023SJohan Hovold .name = "lm3533-backlight",
5616c5c023SJohan Hovold .id = 0,
5716c5c023SJohan Hovold },
5816c5c023SJohan Hovold {
5916c5c023SJohan Hovold .name = "lm3533-backlight",
6016c5c023SJohan Hovold .id = 1,
6116c5c023SJohan Hovold },
6216c5c023SJohan Hovold };
6316c5c023SJohan Hovold
6416c5c023SJohan Hovold static struct mfd_cell lm3533_led_devs[] = {
6516c5c023SJohan Hovold {
6616c5c023SJohan Hovold .name = "lm3533-leds",
6716c5c023SJohan Hovold .id = 0,
6816c5c023SJohan Hovold },
6916c5c023SJohan Hovold {
7016c5c023SJohan Hovold .name = "lm3533-leds",
7116c5c023SJohan Hovold .id = 1,
7216c5c023SJohan Hovold },
7316c5c023SJohan Hovold {
7416c5c023SJohan Hovold .name = "lm3533-leds",
7516c5c023SJohan Hovold .id = 2,
7616c5c023SJohan Hovold },
7716c5c023SJohan Hovold {
7816c5c023SJohan Hovold .name = "lm3533-leds",
7916c5c023SJohan Hovold .id = 3,
8016c5c023SJohan Hovold },
8116c5c023SJohan Hovold };
8216c5c023SJohan Hovold
lm3533_read(struct lm3533 * lm3533,u8 reg,u8 * val)8316c5c023SJohan Hovold int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
8416c5c023SJohan Hovold {
8516c5c023SJohan Hovold int tmp;
8616c5c023SJohan Hovold int ret;
8716c5c023SJohan Hovold
8816c5c023SJohan Hovold ret = regmap_read(lm3533->regmap, reg, &tmp);
8916c5c023SJohan Hovold if (ret < 0) {
9016c5c023SJohan Hovold dev_err(lm3533->dev, "failed to read register %02x: %d\n",
9116c5c023SJohan Hovold reg, ret);
9216c5c023SJohan Hovold return ret;
9316c5c023SJohan Hovold }
9416c5c023SJohan Hovold
9516c5c023SJohan Hovold *val = tmp;
9616c5c023SJohan Hovold
9716c5c023SJohan Hovold dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
9816c5c023SJohan Hovold
9916c5c023SJohan Hovold return ret;
10016c5c023SJohan Hovold }
10116c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_read);
10216c5c023SJohan Hovold
lm3533_write(struct lm3533 * lm3533,u8 reg,u8 val)10316c5c023SJohan Hovold int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
10416c5c023SJohan Hovold {
10516c5c023SJohan Hovold int ret;
10616c5c023SJohan Hovold
10716c5c023SJohan Hovold dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
10816c5c023SJohan Hovold
10916c5c023SJohan Hovold ret = regmap_write(lm3533->regmap, reg, val);
11016c5c023SJohan Hovold if (ret < 0) {
11116c5c023SJohan Hovold dev_err(lm3533->dev, "failed to write register %02x: %d\n",
11216c5c023SJohan Hovold reg, ret);
11316c5c023SJohan Hovold }
11416c5c023SJohan Hovold
11516c5c023SJohan Hovold return ret;
11616c5c023SJohan Hovold }
11716c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_write);
11816c5c023SJohan Hovold
lm3533_update(struct lm3533 * lm3533,u8 reg,u8 val,u8 mask)11916c5c023SJohan Hovold int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
12016c5c023SJohan Hovold {
12116c5c023SJohan Hovold int ret;
12216c5c023SJohan Hovold
12316c5c023SJohan Hovold dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
12416c5c023SJohan Hovold
125664dd066SAxel Lin ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
12616c5c023SJohan Hovold if (ret < 0) {
12716c5c023SJohan Hovold dev_err(lm3533->dev, "failed to update register %02x: %d\n",
12816c5c023SJohan Hovold reg, ret);
12916c5c023SJohan Hovold }
13016c5c023SJohan Hovold
13116c5c023SJohan Hovold return ret;
13216c5c023SJohan Hovold }
13316c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_update);
13416c5c023SJohan Hovold
lm3533_set_boost_freq(struct lm3533 * lm3533,enum lm3533_boost_freq freq)135d9055dc5SJohan Hovold static int lm3533_set_boost_freq(struct lm3533 *lm3533,
136d9055dc5SJohan Hovold enum lm3533_boost_freq freq)
137d9055dc5SJohan Hovold {
138d9055dc5SJohan Hovold int ret;
139d9055dc5SJohan Hovold
140d9055dc5SJohan Hovold ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
141d9055dc5SJohan Hovold freq << LM3533_BOOST_FREQ_SHIFT,
142d9055dc5SJohan Hovold LM3533_BOOST_FREQ_MASK);
143d9055dc5SJohan Hovold if (ret)
144d9055dc5SJohan Hovold dev_err(lm3533->dev, "failed to set boost frequency\n");
145d9055dc5SJohan Hovold
146d9055dc5SJohan Hovold return ret;
147d9055dc5SJohan Hovold }
148d9055dc5SJohan Hovold
149d9055dc5SJohan Hovold
lm3533_set_boost_ovp(struct lm3533 * lm3533,enum lm3533_boost_ovp ovp)150d9055dc5SJohan Hovold static int lm3533_set_boost_ovp(struct lm3533 *lm3533,
151d9055dc5SJohan Hovold enum lm3533_boost_ovp ovp)
152d9055dc5SJohan Hovold {
153d9055dc5SJohan Hovold int ret;
154d9055dc5SJohan Hovold
155d9055dc5SJohan Hovold ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
156d9055dc5SJohan Hovold ovp << LM3533_BOOST_OVP_SHIFT,
157d9055dc5SJohan Hovold LM3533_BOOST_OVP_MASK);
158d9055dc5SJohan Hovold if (ret)
159d9055dc5SJohan Hovold dev_err(lm3533->dev, "failed to set boost ovp\n");
160d9055dc5SJohan Hovold
161d9055dc5SJohan Hovold return ret;
162d9055dc5SJohan Hovold }
163d9055dc5SJohan Hovold
16416c5c023SJohan Hovold /*
16516c5c023SJohan Hovold * HVLED output config -- output hvled controlled by backlight bl
16616c5c023SJohan Hovold */
lm3533_set_hvled_config(struct lm3533 * lm3533,u8 hvled,u8 bl)16716c5c023SJohan Hovold static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
16816c5c023SJohan Hovold {
16916c5c023SJohan Hovold u8 val;
17016c5c023SJohan Hovold u8 mask;
17116c5c023SJohan Hovold int shift;
17216c5c023SJohan Hovold int ret;
17316c5c023SJohan Hovold
17416c5c023SJohan Hovold if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)
17516c5c023SJohan Hovold return -EINVAL;
17616c5c023SJohan Hovold
17716c5c023SJohan Hovold if (bl > LM3533_BL_ID_MAX)
17816c5c023SJohan Hovold return -EINVAL;
17916c5c023SJohan Hovold
18016c5c023SJohan Hovold shift = hvled - 1;
18116c5c023SJohan Hovold mask = LM3533_BL_ID_MASK << shift;
18216c5c023SJohan Hovold val = bl << shift;
18316c5c023SJohan Hovold
18416c5c023SJohan Hovold ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
18516c5c023SJohan Hovold if (ret)
18616c5c023SJohan Hovold dev_err(lm3533->dev, "failed to set hvled config\n");
18716c5c023SJohan Hovold
18816c5c023SJohan Hovold return ret;
18916c5c023SJohan Hovold }
19016c5c023SJohan Hovold
19116c5c023SJohan Hovold /*
19216c5c023SJohan Hovold * LVLED output config -- output lvled controlled by LED led
19316c5c023SJohan Hovold */
lm3533_set_lvled_config(struct lm3533 * lm3533,u8 lvled,u8 led)19416c5c023SJohan Hovold static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
19516c5c023SJohan Hovold {
19616c5c023SJohan Hovold u8 reg;
19716c5c023SJohan Hovold u8 val;
19816c5c023SJohan Hovold u8 mask;
19916c5c023SJohan Hovold int shift;
20016c5c023SJohan Hovold int ret;
20116c5c023SJohan Hovold
20216c5c023SJohan Hovold if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)
20316c5c023SJohan Hovold return -EINVAL;
20416c5c023SJohan Hovold
20516c5c023SJohan Hovold if (led > LM3533_LED_ID_MAX)
20616c5c023SJohan Hovold return -EINVAL;
20716c5c023SJohan Hovold
20816c5c023SJohan Hovold if (lvled < 4) {
20916c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF1;
21016c5c023SJohan Hovold shift = 2 * lvled;
21116c5c023SJohan Hovold } else {
21216c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF2;
21316c5c023SJohan Hovold shift = 2 * (lvled - 4);
21416c5c023SJohan Hovold }
21516c5c023SJohan Hovold
21616c5c023SJohan Hovold mask = LM3533_LED_ID_MASK << shift;
21716c5c023SJohan Hovold val = led << shift;
21816c5c023SJohan Hovold
21916c5c023SJohan Hovold ret = lm3533_update(lm3533, reg, val, mask);
22016c5c023SJohan Hovold if (ret)
22116c5c023SJohan Hovold dev_err(lm3533->dev, "failed to set lvled config\n");
22216c5c023SJohan Hovold
22316c5c023SJohan Hovold return ret;
22416c5c023SJohan Hovold }
22516c5c023SJohan Hovold
lm3533_enable(struct lm3533 * lm3533)22616c5c023SJohan Hovold static void lm3533_enable(struct lm3533 *lm3533)
22716c5c023SJohan Hovold {
22816c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen))
22916c5c023SJohan Hovold gpio_set_value(lm3533->gpio_hwen, 1);
23016c5c023SJohan Hovold }
23116c5c023SJohan Hovold
lm3533_disable(struct lm3533 * lm3533)23216c5c023SJohan Hovold static void lm3533_disable(struct lm3533 *lm3533)
23316c5c023SJohan Hovold {
23416c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen))
23516c5c023SJohan Hovold gpio_set_value(lm3533->gpio_hwen, 0);
23616c5c023SJohan Hovold }
23716c5c023SJohan Hovold
23816c5c023SJohan Hovold enum lm3533_attribute_type {
23916c5c023SJohan Hovold LM3533_ATTR_TYPE_BACKLIGHT,
24016c5c023SJohan Hovold LM3533_ATTR_TYPE_LED,
24116c5c023SJohan Hovold };
24216c5c023SJohan Hovold
24316c5c023SJohan Hovold struct lm3533_device_attribute {
24416c5c023SJohan Hovold struct device_attribute dev_attr;
24516c5c023SJohan Hovold enum lm3533_attribute_type type;
24616c5c023SJohan Hovold union {
24716c5c023SJohan Hovold struct {
24816c5c023SJohan Hovold u8 id;
24916c5c023SJohan Hovold } output;
25016c5c023SJohan Hovold } u;
25116c5c023SJohan Hovold };
25216c5c023SJohan Hovold
25316c5c023SJohan Hovold #define to_lm3533_dev_attr(_attr) \
25416c5c023SJohan Hovold container_of(_attr, struct lm3533_device_attribute, dev_attr)
25516c5c023SJohan Hovold
show_output(struct device * dev,struct device_attribute * attr,char * buf)25616c5c023SJohan Hovold static ssize_t show_output(struct device *dev,
25716c5c023SJohan Hovold struct device_attribute *attr, char *buf)
25816c5c023SJohan Hovold {
25916c5c023SJohan Hovold struct lm3533 *lm3533 = dev_get_drvdata(dev);
26016c5c023SJohan Hovold struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
26116c5c023SJohan Hovold int id = lattr->u.output.id;
26216c5c023SJohan Hovold u8 reg;
26316c5c023SJohan Hovold u8 val;
26416c5c023SJohan Hovold u8 mask;
26516c5c023SJohan Hovold int shift;
26616c5c023SJohan Hovold int ret;
26716c5c023SJohan Hovold
26816c5c023SJohan Hovold if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {
26916c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF1;
27016c5c023SJohan Hovold shift = id - 1;
27116c5c023SJohan Hovold mask = LM3533_BL_ID_MASK << shift;
27216c5c023SJohan Hovold } else {
27316c5c023SJohan Hovold if (id < 4) {
27416c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF1;
27516c5c023SJohan Hovold shift = 2 * id;
27616c5c023SJohan Hovold } else {
27716c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF2;
27816c5c023SJohan Hovold shift = 2 * (id - 4);
27916c5c023SJohan Hovold }
28016c5c023SJohan Hovold mask = LM3533_LED_ID_MASK << shift;
28116c5c023SJohan Hovold }
28216c5c023SJohan Hovold
28316c5c023SJohan Hovold ret = lm3533_read(lm3533, reg, &val);
28416c5c023SJohan Hovold if (ret)
28516c5c023SJohan Hovold return ret;
28616c5c023SJohan Hovold
28716c5c023SJohan Hovold val = (val & mask) >> shift;
28816c5c023SJohan Hovold
2898cc5e62bSye xingchen return sysfs_emit(buf, "%u\n", val);
29016c5c023SJohan Hovold }
29116c5c023SJohan Hovold
store_output(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)29216c5c023SJohan Hovold static ssize_t store_output(struct device *dev,
29316c5c023SJohan Hovold struct device_attribute *attr,
29416c5c023SJohan Hovold const char *buf, size_t len)
29516c5c023SJohan Hovold {
29616c5c023SJohan Hovold struct lm3533 *lm3533 = dev_get_drvdata(dev);
29716c5c023SJohan Hovold struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
29816c5c023SJohan Hovold int id = lattr->u.output.id;
29916c5c023SJohan Hovold u8 val;
30016c5c023SJohan Hovold int ret;
30116c5c023SJohan Hovold
30216c5c023SJohan Hovold if (kstrtou8(buf, 0, &val))
30316c5c023SJohan Hovold return -EINVAL;
30416c5c023SJohan Hovold
30516c5c023SJohan Hovold if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)
30616c5c023SJohan Hovold ret = lm3533_set_hvled_config(lm3533, id, val);
30716c5c023SJohan Hovold else
30816c5c023SJohan Hovold ret = lm3533_set_lvled_config(lm3533, id, val);
30916c5c023SJohan Hovold
31016c5c023SJohan Hovold if (ret)
31116c5c023SJohan Hovold return ret;
31216c5c023SJohan Hovold
31316c5c023SJohan Hovold return len;
31416c5c023SJohan Hovold }
31516c5c023SJohan Hovold
31616c5c023SJohan Hovold #define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \
31716c5c023SJohan Hovold struct lm3533_device_attribute lm3533_dev_attr_##_name = \
31816c5c023SJohan Hovold { .dev_attr = __ATTR(_name, _mode, _show, _store), \
31916c5c023SJohan Hovold .type = _type, \
32016c5c023SJohan Hovold .u.output = { .id = _id }, }
32116c5c023SJohan Hovold
32216c5c023SJohan Hovold #define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \
32316c5c023SJohan Hovold LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \
32416c5c023SJohan Hovold show_output, store_output, _type, _id)
32516c5c023SJohan Hovold
32616c5c023SJohan Hovold #define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \
32716c5c023SJohan Hovold LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)
32816c5c023SJohan Hovold #define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \
32916c5c023SJohan Hovold LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)
33016c5c023SJohan Hovold /*
33116c5c023SJohan Hovold * Output config:
33216c5c023SJohan Hovold *
33316c5c023SJohan Hovold * output_hvled<nr> 0-1
33416c5c023SJohan Hovold * output_lvled<nr> 0-3
33516c5c023SJohan Hovold */
33616c5c023SJohan Hovold static LM3533_OUTPUT_HVLED_ATTR_RW(1);
33716c5c023SJohan Hovold static LM3533_OUTPUT_HVLED_ATTR_RW(2);
33816c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(1);
33916c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(2);
34016c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(3);
34116c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(4);
34216c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(5);
34316c5c023SJohan Hovold
34416c5c023SJohan Hovold static struct attribute *lm3533_attributes[] = {
34516c5c023SJohan Hovold &lm3533_dev_attr_output_hvled1.dev_attr.attr,
34616c5c023SJohan Hovold &lm3533_dev_attr_output_hvled2.dev_attr.attr,
34716c5c023SJohan Hovold &lm3533_dev_attr_output_lvled1.dev_attr.attr,
34816c5c023SJohan Hovold &lm3533_dev_attr_output_lvled2.dev_attr.attr,
34916c5c023SJohan Hovold &lm3533_dev_attr_output_lvled3.dev_attr.attr,
35016c5c023SJohan Hovold &lm3533_dev_attr_output_lvled4.dev_attr.attr,
35116c5c023SJohan Hovold &lm3533_dev_attr_output_lvled5.dev_attr.attr,
35216c5c023SJohan Hovold NULL,
35316c5c023SJohan Hovold };
35416c5c023SJohan Hovold
35516c5c023SJohan Hovold #define to_dev_attr(_attr) \
35616c5c023SJohan Hovold container_of(_attr, struct device_attribute, attr)
35716c5c023SJohan Hovold
lm3533_attr_is_visible(struct kobject * kobj,struct attribute * attr,int n)358168755ebSDan Carpenter static umode_t lm3533_attr_is_visible(struct kobject *kobj,
35916c5c023SJohan Hovold struct attribute *attr, int n)
36016c5c023SJohan Hovold {
36123144a32SYang Li struct device *dev = kobj_to_dev(kobj);
36216c5c023SJohan Hovold struct lm3533 *lm3533 = dev_get_drvdata(dev);
36316c5c023SJohan Hovold struct device_attribute *dattr = to_dev_attr(attr);
36416c5c023SJohan Hovold struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
36516c5c023SJohan Hovold enum lm3533_attribute_type type = lattr->type;
36660908855SJohan Hovold umode_t mode = attr->mode;
36716c5c023SJohan Hovold
36816c5c023SJohan Hovold if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)
36916c5c023SJohan Hovold mode = 0;
37016c5c023SJohan Hovold else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)
37116c5c023SJohan Hovold mode = 0;
37216c5c023SJohan Hovold
37316c5c023SJohan Hovold return mode;
37416c5c023SJohan Hovold };
37516c5c023SJohan Hovold
37616c5c023SJohan Hovold static struct attribute_group lm3533_attribute_group = {
37716c5c023SJohan Hovold .is_visible = lm3533_attr_is_visible,
37816c5c023SJohan Hovold .attrs = lm3533_attributes
37916c5c023SJohan Hovold };
38016c5c023SJohan Hovold
lm3533_device_als_init(struct lm3533 * lm3533)381f791be49SBill Pemberton static int lm3533_device_als_init(struct lm3533 *lm3533)
38216c5c023SJohan Hovold {
383334a41ceSJingoo Han struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
38416c5c023SJohan Hovold int ret;
38516c5c023SJohan Hovold
38616c5c023SJohan Hovold if (!pdata->als)
38716c5c023SJohan Hovold return 0;
38816c5c023SJohan Hovold
38916c5c023SJohan Hovold lm3533_als_devs[0].platform_data = pdata->als;
39016c5c023SJohan Hovold lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
39116c5c023SJohan Hovold
3920848c94fSMark Brown ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,
3930848c94fSMark Brown 0, NULL);
39416c5c023SJohan Hovold if (ret) {
39516c5c023SJohan Hovold dev_err(lm3533->dev, "failed to add ALS device\n");
39616c5c023SJohan Hovold return ret;
39716c5c023SJohan Hovold }
39816c5c023SJohan Hovold
39916c5c023SJohan Hovold lm3533->have_als = 1;
40016c5c023SJohan Hovold
40116c5c023SJohan Hovold return 0;
40216c5c023SJohan Hovold }
40316c5c023SJohan Hovold
lm3533_device_bl_init(struct lm3533 * lm3533)404f791be49SBill Pemberton static int lm3533_device_bl_init(struct lm3533 *lm3533)
40516c5c023SJohan Hovold {
406334a41ceSJingoo Han struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
40716c5c023SJohan Hovold int i;
40816c5c023SJohan Hovold int ret;
40916c5c023SJohan Hovold
41016c5c023SJohan Hovold if (!pdata->backlights || pdata->num_backlights == 0)
41116c5c023SJohan Hovold return 0;
41216c5c023SJohan Hovold
41316c5c023SJohan Hovold if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
41416c5c023SJohan Hovold pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
41516c5c023SJohan Hovold
41616c5c023SJohan Hovold for (i = 0; i < pdata->num_backlights; ++i) {
41716c5c023SJohan Hovold lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
41816c5c023SJohan Hovold lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
41916c5c023SJohan Hovold }
42016c5c023SJohan Hovold
42116c5c023SJohan Hovold ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
4220848c94fSMark Brown pdata->num_backlights, NULL, 0, NULL);
42316c5c023SJohan Hovold if (ret) {
42416c5c023SJohan Hovold dev_err(lm3533->dev, "failed to add backlight devices\n");
42516c5c023SJohan Hovold return ret;
42616c5c023SJohan Hovold }
42716c5c023SJohan Hovold
42816c5c023SJohan Hovold lm3533->have_backlights = 1;
42916c5c023SJohan Hovold
43016c5c023SJohan Hovold return 0;
43116c5c023SJohan Hovold }
43216c5c023SJohan Hovold
lm3533_device_led_init(struct lm3533 * lm3533)433f791be49SBill Pemberton static int lm3533_device_led_init(struct lm3533 *lm3533)
43416c5c023SJohan Hovold {
435334a41ceSJingoo Han struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
43616c5c023SJohan Hovold int i;
43716c5c023SJohan Hovold int ret;
43816c5c023SJohan Hovold
43916c5c023SJohan Hovold if (!pdata->leds || pdata->num_leds == 0)
44016c5c023SJohan Hovold return 0;
44116c5c023SJohan Hovold
44216c5c023SJohan Hovold if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
44316c5c023SJohan Hovold pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
44416c5c023SJohan Hovold
44516c5c023SJohan Hovold for (i = 0; i < pdata->num_leds; ++i) {
44616c5c023SJohan Hovold lm3533_led_devs[i].platform_data = &pdata->leds[i];
44716c5c023SJohan Hovold lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
44816c5c023SJohan Hovold }
44916c5c023SJohan Hovold
45016c5c023SJohan Hovold ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
4510848c94fSMark Brown pdata->num_leds, NULL, 0, NULL);
45216c5c023SJohan Hovold if (ret) {
45316c5c023SJohan Hovold dev_err(lm3533->dev, "failed to add LED devices\n");
45416c5c023SJohan Hovold return ret;
45516c5c023SJohan Hovold }
45616c5c023SJohan Hovold
45716c5c023SJohan Hovold lm3533->have_leds = 1;
45816c5c023SJohan Hovold
45916c5c023SJohan Hovold return 0;
46016c5c023SJohan Hovold }
46116c5c023SJohan Hovold
lm3533_device_setup(struct lm3533 * lm3533,struct lm3533_platform_data * pdata)462f791be49SBill Pemberton static int lm3533_device_setup(struct lm3533 *lm3533,
463d9055dc5SJohan Hovold struct lm3533_platform_data *pdata)
464d9055dc5SJohan Hovold {
465d9055dc5SJohan Hovold int ret;
466d9055dc5SJohan Hovold
467d9055dc5SJohan Hovold ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);
468d9055dc5SJohan Hovold if (ret)
469d9055dc5SJohan Hovold return ret;
470d9055dc5SJohan Hovold
471a1c16d71SJavier Martinez Canillas return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);
472d9055dc5SJohan Hovold }
473d9055dc5SJohan Hovold
lm3533_device_init(struct lm3533 * lm3533)474f791be49SBill Pemberton static int lm3533_device_init(struct lm3533 *lm3533)
47516c5c023SJohan Hovold {
476334a41ceSJingoo Han struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
47716c5c023SJohan Hovold int ret;
47816c5c023SJohan Hovold
47916c5c023SJohan Hovold dev_dbg(lm3533->dev, "%s\n", __func__);
48016c5c023SJohan Hovold
48116c5c023SJohan Hovold if (!pdata) {
48216c5c023SJohan Hovold dev_err(lm3533->dev, "no platform data\n");
48316c5c023SJohan Hovold return -EINVAL;
48416c5c023SJohan Hovold }
48516c5c023SJohan Hovold
48616c5c023SJohan Hovold lm3533->gpio_hwen = pdata->gpio_hwen;
48716c5c023SJohan Hovold
48816c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen)) {
489bf5ea28aSJingoo Han ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen,
490bf5ea28aSJingoo Han GPIOF_OUT_INIT_LOW, "lm3533-hwen");
49116c5c023SJohan Hovold if (ret < 0) {
49216c5c023SJohan Hovold dev_err(lm3533->dev,
49316c5c023SJohan Hovold "failed to request HWEN GPIO %d\n",
49416c5c023SJohan Hovold lm3533->gpio_hwen);
49516c5c023SJohan Hovold return ret;
49616c5c023SJohan Hovold }
49716c5c023SJohan Hovold }
49816c5c023SJohan Hovold
49916c5c023SJohan Hovold lm3533_enable(lm3533);
50016c5c023SJohan Hovold
501d9055dc5SJohan Hovold ret = lm3533_device_setup(lm3533, pdata);
502d9055dc5SJohan Hovold if (ret)
503d9055dc5SJohan Hovold goto err_disable;
504d9055dc5SJohan Hovold
50516c5c023SJohan Hovold lm3533_device_als_init(lm3533);
50616c5c023SJohan Hovold lm3533_device_bl_init(lm3533);
50716c5c023SJohan Hovold lm3533_device_led_init(lm3533);
50816c5c023SJohan Hovold
50916c5c023SJohan Hovold ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
51016c5c023SJohan Hovold if (ret < 0) {
51116c5c023SJohan Hovold dev_err(lm3533->dev, "failed to create sysfs attributes\n");
51216c5c023SJohan Hovold goto err_unregister;
51316c5c023SJohan Hovold }
51416c5c023SJohan Hovold
51516c5c023SJohan Hovold return 0;
51616c5c023SJohan Hovold
51716c5c023SJohan Hovold err_unregister:
51816c5c023SJohan Hovold mfd_remove_devices(lm3533->dev);
519d9055dc5SJohan Hovold err_disable:
52016c5c023SJohan Hovold lm3533_disable(lm3533);
52116c5c023SJohan Hovold
52216c5c023SJohan Hovold return ret;
52316c5c023SJohan Hovold }
52416c5c023SJohan Hovold
lm3533_device_exit(struct lm3533 * lm3533)5254740f73fSBill Pemberton static void lm3533_device_exit(struct lm3533 *lm3533)
52616c5c023SJohan Hovold {
52716c5c023SJohan Hovold dev_dbg(lm3533->dev, "%s\n", __func__);
52816c5c023SJohan Hovold
52916c5c023SJohan Hovold sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
53016c5c023SJohan Hovold
53116c5c023SJohan Hovold mfd_remove_devices(lm3533->dev);
53216c5c023SJohan Hovold lm3533_disable(lm3533);
53316c5c023SJohan Hovold }
53416c5c023SJohan Hovold
lm3533_readable_register(struct device * dev,unsigned int reg)53516c5c023SJohan Hovold static bool lm3533_readable_register(struct device *dev, unsigned int reg)
53616c5c023SJohan Hovold {
53716c5c023SJohan Hovold switch (reg) {
53816c5c023SJohan Hovold case 0x10 ... 0x2c:
53916c5c023SJohan Hovold case 0x30 ... 0x38:
54016c5c023SJohan Hovold case 0x40 ... 0x45:
54116c5c023SJohan Hovold case 0x50 ... 0x57:
54216c5c023SJohan Hovold case 0x60 ... 0x6e:
54316c5c023SJohan Hovold case 0x70 ... 0x75:
54416c5c023SJohan Hovold case 0x80 ... 0x85:
54516c5c023SJohan Hovold case 0x90 ... 0x95:
54616c5c023SJohan Hovold case 0xa0 ... 0xa5:
54716c5c023SJohan Hovold case 0xb0 ... 0xb2:
54816c5c023SJohan Hovold return true;
54916c5c023SJohan Hovold default:
55016c5c023SJohan Hovold return false;
55116c5c023SJohan Hovold }
55216c5c023SJohan Hovold }
55316c5c023SJohan Hovold
lm3533_volatile_register(struct device * dev,unsigned int reg)55416c5c023SJohan Hovold static bool lm3533_volatile_register(struct device *dev, unsigned int reg)
55516c5c023SJohan Hovold {
55616c5c023SJohan Hovold switch (reg) {
557c48bf153SJohan Hovold case 0x34 ... 0x36: /* zone */
55816c5c023SJohan Hovold case 0x37 ... 0x38: /* adc */
55916c5c023SJohan Hovold case 0xb0 ... 0xb1: /* fault */
56016c5c023SJohan Hovold return true;
56116c5c023SJohan Hovold default:
56216c5c023SJohan Hovold return false;
56316c5c023SJohan Hovold }
56416c5c023SJohan Hovold }
56516c5c023SJohan Hovold
lm3533_precious_register(struct device * dev,unsigned int reg)56616c5c023SJohan Hovold static bool lm3533_precious_register(struct device *dev, unsigned int reg)
56716c5c023SJohan Hovold {
56816c5c023SJohan Hovold switch (reg) {
56916c5c023SJohan Hovold case 0x34: /* zone */
57016c5c023SJohan Hovold return true;
57116c5c023SJohan Hovold default:
57216c5c023SJohan Hovold return false;
57316c5c023SJohan Hovold }
57416c5c023SJohan Hovold }
57516c5c023SJohan Hovold
576dd635161SKrzysztof Kozlowski static const struct regmap_config regmap_config = {
57716c5c023SJohan Hovold .reg_bits = 8,
57816c5c023SJohan Hovold .val_bits = 8,
57916c5c023SJohan Hovold .max_register = LM3533_REG_MAX,
58016c5c023SJohan Hovold .readable_reg = lm3533_readable_register,
58116c5c023SJohan Hovold .volatile_reg = lm3533_volatile_register,
58216c5c023SJohan Hovold .precious_reg = lm3533_precious_register,
58316c5c023SJohan Hovold };
58416c5c023SJohan Hovold
lm3533_i2c_probe(struct i2c_client * i2c)585daf811fcSUwe Kleine-König static int lm3533_i2c_probe(struct i2c_client *i2c)
58616c5c023SJohan Hovold {
58716c5c023SJohan Hovold struct lm3533 *lm3533;
58816c5c023SJohan Hovold
58916c5c023SJohan Hovold dev_dbg(&i2c->dev, "%s\n", __func__);
59016c5c023SJohan Hovold
591fa648e51SJohan Hovold lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL);
59216c5c023SJohan Hovold if (!lm3533)
59316c5c023SJohan Hovold return -ENOMEM;
59416c5c023SJohan Hovold
59516c5c023SJohan Hovold i2c_set_clientdata(i2c, lm3533);
59616c5c023SJohan Hovold
597fa648e51SJohan Hovold lm3533->regmap = devm_regmap_init_i2c(i2c, ®map_config);
598fa648e51SJohan Hovold if (IS_ERR(lm3533->regmap))
599fa648e51SJohan Hovold return PTR_ERR(lm3533->regmap);
60016c5c023SJohan Hovold
60116c5c023SJohan Hovold lm3533->dev = &i2c->dev;
60216c5c023SJohan Hovold lm3533->irq = i2c->irq;
60316c5c023SJohan Hovold
604a1c16d71SJavier Martinez Canillas return lm3533_device_init(lm3533);
60516c5c023SJohan Hovold }
60616c5c023SJohan Hovold
lm3533_i2c_remove(struct i2c_client * i2c)607ed5c2f5fSUwe Kleine-König static void lm3533_i2c_remove(struct i2c_client *i2c)
60816c5c023SJohan Hovold {
60916c5c023SJohan Hovold struct lm3533 *lm3533 = i2c_get_clientdata(i2c);
61016c5c023SJohan Hovold
61116c5c023SJohan Hovold dev_dbg(&i2c->dev, "%s\n", __func__);
61216c5c023SJohan Hovold
61316c5c023SJohan Hovold lm3533_device_exit(lm3533);
61416c5c023SJohan Hovold }
61516c5c023SJohan Hovold
61616c5c023SJohan Hovold static const struct i2c_device_id lm3533_i2c_ids[] = {
61716c5c023SJohan Hovold { "lm3533", 0 },
61816c5c023SJohan Hovold { },
61916c5c023SJohan Hovold };
62016c5c023SJohan Hovold MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
62116c5c023SJohan Hovold
62216c5c023SJohan Hovold static struct i2c_driver lm3533_i2c_driver = {
62316c5c023SJohan Hovold .driver = {
62416c5c023SJohan Hovold .name = "lm3533",
62516c5c023SJohan Hovold },
62616c5c023SJohan Hovold .id_table = lm3533_i2c_ids,
627*9816d859SUwe Kleine-König .probe = lm3533_i2c_probe,
62884449216SBill Pemberton .remove = lm3533_i2c_remove,
62916c5c023SJohan Hovold };
63016c5c023SJohan Hovold
lm3533_i2c_init(void)63116c5c023SJohan Hovold static int __init lm3533_i2c_init(void)
63216c5c023SJohan Hovold {
63316c5c023SJohan Hovold return i2c_add_driver(&lm3533_i2c_driver);
63416c5c023SJohan Hovold }
63516c5c023SJohan Hovold subsys_initcall(lm3533_i2c_init);
63616c5c023SJohan Hovold
lm3533_i2c_exit(void)63716c5c023SJohan Hovold static void __exit lm3533_i2c_exit(void)
63816c5c023SJohan Hovold {
63916c5c023SJohan Hovold i2c_del_driver(&lm3533_i2c_driver);
64016c5c023SJohan Hovold }
64116c5c023SJohan Hovold module_exit(lm3533_i2c_exit);
64216c5c023SJohan Hovold
64316c5c023SJohan Hovold MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
64416c5c023SJohan Hovold MODULE_DESCRIPTION("LM3533 Core");
64516c5c023SJohan Hovold MODULE_LICENSE("GPL");
646