Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * lm3533-core.c -- LM3533 Core
0004  *
0005  * Copyright (C) 2011-2012 Texas Instruments
0006  *
0007  * Author: Johan Hovold <jhovold@gmail.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/err.h>
0014 #include <linux/gpio.h>
0015 #include <linux/i2c.h>
0016 #include <linux/mfd/core.h>
0017 #include <linux/regmap.h>
0018 #include <linux/seq_file.h>
0019 #include <linux/slab.h>
0020 #include <linux/uaccess.h>
0021 
0022 #include <linux/mfd/lm3533.h>
0023 
0024 
0025 #define LM3533_BOOST_OVP_MASK       0x06
0026 #define LM3533_BOOST_OVP_SHIFT      1
0027 
0028 #define LM3533_BOOST_FREQ_MASK      0x01
0029 #define LM3533_BOOST_FREQ_SHIFT     0
0030 
0031 #define LM3533_BL_ID_MASK       1
0032 #define LM3533_LED_ID_MASK      3
0033 #define LM3533_BL_ID_MAX        1
0034 #define LM3533_LED_ID_MAX       3
0035 
0036 #define LM3533_HVLED_ID_MAX     2
0037 #define LM3533_LVLED_ID_MAX     5
0038 
0039 #define LM3533_REG_OUTPUT_CONF1     0x10
0040 #define LM3533_REG_OUTPUT_CONF2     0x11
0041 #define LM3533_REG_BOOST_PWM        0x2c
0042 
0043 #define LM3533_REG_MAX          0xb2
0044 
0045 
0046 static struct mfd_cell lm3533_als_devs[] = {
0047     {
0048         .name   = "lm3533-als",
0049         .id = -1,
0050     },
0051 };
0052 
0053 static struct mfd_cell lm3533_bl_devs[] = {
0054     {
0055         .name   = "lm3533-backlight",
0056         .id = 0,
0057     },
0058     {
0059         .name   = "lm3533-backlight",
0060         .id = 1,
0061     },
0062 };
0063 
0064 static struct mfd_cell lm3533_led_devs[] = {
0065     {
0066         .name   = "lm3533-leds",
0067         .id = 0,
0068     },
0069     {
0070         .name   = "lm3533-leds",
0071         .id = 1,
0072     },
0073     {
0074         .name   = "lm3533-leds",
0075         .id = 2,
0076     },
0077     {
0078         .name   = "lm3533-leds",
0079         .id = 3,
0080     },
0081 };
0082 
0083 int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
0084 {
0085     int tmp;
0086     int ret;
0087 
0088     ret = regmap_read(lm3533->regmap, reg, &tmp);
0089     if (ret < 0) {
0090         dev_err(lm3533->dev, "failed to read register %02x: %d\n",
0091                                 reg, ret);
0092         return ret;
0093     }
0094 
0095     *val = tmp;
0096 
0097     dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
0098 
0099     return ret;
0100 }
0101 EXPORT_SYMBOL_GPL(lm3533_read);
0102 
0103 int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
0104 {
0105     int ret;
0106 
0107     dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
0108 
0109     ret = regmap_write(lm3533->regmap, reg, val);
0110     if (ret < 0) {
0111         dev_err(lm3533->dev, "failed to write register %02x: %d\n",
0112                                 reg, ret);
0113     }
0114 
0115     return ret;
0116 }
0117 EXPORT_SYMBOL_GPL(lm3533_write);
0118 
0119 int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
0120 {
0121     int ret;
0122 
0123     dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
0124 
0125     ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
0126     if (ret < 0) {
0127         dev_err(lm3533->dev, "failed to update register %02x: %d\n",
0128                                 reg, ret);
0129     }
0130 
0131     return ret;
0132 }
0133 EXPORT_SYMBOL_GPL(lm3533_update);
0134 
0135 static int lm3533_set_boost_freq(struct lm3533 *lm3533,
0136                         enum lm3533_boost_freq freq)
0137 {
0138     int ret;
0139 
0140     ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
0141                     freq << LM3533_BOOST_FREQ_SHIFT,
0142                     LM3533_BOOST_FREQ_MASK);
0143     if (ret)
0144         dev_err(lm3533->dev, "failed to set boost frequency\n");
0145 
0146     return ret;
0147 }
0148 
0149 
0150 static int lm3533_set_boost_ovp(struct lm3533 *lm3533,
0151                         enum lm3533_boost_ovp ovp)
0152 {
0153     int ret;
0154 
0155     ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
0156                     ovp << LM3533_BOOST_OVP_SHIFT,
0157                     LM3533_BOOST_OVP_MASK);
0158     if (ret)
0159         dev_err(lm3533->dev, "failed to set boost ovp\n");
0160 
0161     return ret;
0162 }
0163 
0164 /*
0165  * HVLED output config -- output hvled controlled by backlight bl
0166  */
0167 static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
0168 {
0169     u8 val;
0170     u8 mask;
0171     int shift;
0172     int ret;
0173 
0174     if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)
0175         return -EINVAL;
0176 
0177     if (bl > LM3533_BL_ID_MAX)
0178         return -EINVAL;
0179 
0180     shift = hvled - 1;
0181     mask = LM3533_BL_ID_MASK << shift;
0182     val = bl << shift;
0183 
0184     ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
0185     if (ret)
0186         dev_err(lm3533->dev, "failed to set hvled config\n");
0187 
0188     return ret;
0189 }
0190 
0191 /*
0192  * LVLED output config -- output lvled controlled by LED led
0193  */
0194 static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
0195 {
0196     u8 reg;
0197     u8 val;
0198     u8 mask;
0199     int shift;
0200     int ret;
0201 
0202     if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)
0203         return -EINVAL;
0204 
0205     if (led > LM3533_LED_ID_MAX)
0206         return -EINVAL;
0207 
0208     if (lvled < 4) {
0209         reg = LM3533_REG_OUTPUT_CONF1;
0210         shift = 2 * lvled;
0211     } else {
0212         reg = LM3533_REG_OUTPUT_CONF2;
0213         shift = 2 * (lvled - 4);
0214     }
0215 
0216     mask = LM3533_LED_ID_MASK << shift;
0217     val = led << shift;
0218 
0219     ret = lm3533_update(lm3533, reg, val, mask);
0220     if (ret)
0221         dev_err(lm3533->dev, "failed to set lvled config\n");
0222 
0223     return ret;
0224 }
0225 
0226 static void lm3533_enable(struct lm3533 *lm3533)
0227 {
0228     if (gpio_is_valid(lm3533->gpio_hwen))
0229         gpio_set_value(lm3533->gpio_hwen, 1);
0230 }
0231 
0232 static void lm3533_disable(struct lm3533 *lm3533)
0233 {
0234     if (gpio_is_valid(lm3533->gpio_hwen))
0235         gpio_set_value(lm3533->gpio_hwen, 0);
0236 }
0237 
0238 enum lm3533_attribute_type {
0239     LM3533_ATTR_TYPE_BACKLIGHT,
0240     LM3533_ATTR_TYPE_LED,
0241 };
0242 
0243 struct lm3533_device_attribute {
0244     struct device_attribute dev_attr;
0245     enum lm3533_attribute_type type;
0246     union {
0247         struct {
0248             u8 id;
0249         } output;
0250     } u;
0251 };
0252 
0253 #define to_lm3533_dev_attr(_attr) \
0254     container_of(_attr, struct lm3533_device_attribute, dev_attr)
0255 
0256 static ssize_t show_output(struct device *dev,
0257                 struct device_attribute *attr, char *buf)
0258 {
0259     struct lm3533 *lm3533 = dev_get_drvdata(dev);
0260     struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
0261     int id = lattr->u.output.id;
0262     u8 reg;
0263     u8 val;
0264     u8 mask;
0265     int shift;
0266     int ret;
0267 
0268     if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {
0269         reg = LM3533_REG_OUTPUT_CONF1;
0270         shift = id - 1;
0271         mask = LM3533_BL_ID_MASK << shift;
0272     } else {
0273         if (id < 4) {
0274             reg = LM3533_REG_OUTPUT_CONF1;
0275             shift = 2 * id;
0276         } else {
0277             reg = LM3533_REG_OUTPUT_CONF2;
0278             shift = 2 * (id - 4);
0279         }
0280         mask = LM3533_LED_ID_MASK << shift;
0281     }
0282 
0283     ret = lm3533_read(lm3533, reg, &val);
0284     if (ret)
0285         return ret;
0286 
0287     val = (val & mask) >> shift;
0288 
0289     return scnprintf(buf, PAGE_SIZE, "%u\n", val);
0290 }
0291 
0292 static ssize_t store_output(struct device *dev,
0293                     struct device_attribute *attr,
0294                     const char *buf, size_t len)
0295 {
0296     struct lm3533 *lm3533 = dev_get_drvdata(dev);
0297     struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
0298     int id = lattr->u.output.id;
0299     u8 val;
0300     int ret;
0301 
0302     if (kstrtou8(buf, 0, &val))
0303         return -EINVAL;
0304 
0305     if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)
0306         ret = lm3533_set_hvled_config(lm3533, id, val);
0307     else
0308         ret = lm3533_set_lvled_config(lm3533, id, val);
0309 
0310     if (ret)
0311         return ret;
0312 
0313     return len;
0314 }
0315 
0316 #define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \
0317     struct lm3533_device_attribute lm3533_dev_attr_##_name = \
0318         { .dev_attr = __ATTR(_name, _mode, _show, _store), \
0319           .type     = _type, \
0320           .u.output = { .id = _id }, }
0321 
0322 #define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \
0323     LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \
0324                     show_output, store_output, _type, _id)
0325 
0326 #define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \
0327     LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)
0328 #define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \
0329     LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)
0330 /*
0331  * Output config:
0332  *
0333  * output_hvled<nr> 0-1
0334  * output_lvled<nr> 0-3
0335  */
0336 static LM3533_OUTPUT_HVLED_ATTR_RW(1);
0337 static LM3533_OUTPUT_HVLED_ATTR_RW(2);
0338 static LM3533_OUTPUT_LVLED_ATTR_RW(1);
0339 static LM3533_OUTPUT_LVLED_ATTR_RW(2);
0340 static LM3533_OUTPUT_LVLED_ATTR_RW(3);
0341 static LM3533_OUTPUT_LVLED_ATTR_RW(4);
0342 static LM3533_OUTPUT_LVLED_ATTR_RW(5);
0343 
0344 static struct attribute *lm3533_attributes[] = {
0345     &lm3533_dev_attr_output_hvled1.dev_attr.attr,
0346     &lm3533_dev_attr_output_hvled2.dev_attr.attr,
0347     &lm3533_dev_attr_output_lvled1.dev_attr.attr,
0348     &lm3533_dev_attr_output_lvled2.dev_attr.attr,
0349     &lm3533_dev_attr_output_lvled3.dev_attr.attr,
0350     &lm3533_dev_attr_output_lvled4.dev_attr.attr,
0351     &lm3533_dev_attr_output_lvled5.dev_attr.attr,
0352     NULL,
0353 };
0354 
0355 #define to_dev_attr(_attr) \
0356     container_of(_attr, struct device_attribute, attr)
0357 
0358 static umode_t lm3533_attr_is_visible(struct kobject *kobj,
0359                          struct attribute *attr, int n)
0360 {
0361     struct device *dev = kobj_to_dev(kobj);
0362     struct lm3533 *lm3533 = dev_get_drvdata(dev);
0363     struct device_attribute *dattr = to_dev_attr(attr);
0364     struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
0365     enum lm3533_attribute_type type = lattr->type;
0366     umode_t mode = attr->mode;
0367 
0368     if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)
0369         mode = 0;
0370     else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)
0371         mode = 0;
0372 
0373     return mode;
0374 };
0375 
0376 static struct attribute_group lm3533_attribute_group = {
0377     .is_visible = lm3533_attr_is_visible,
0378     .attrs      = lm3533_attributes
0379 };
0380 
0381 static int lm3533_device_als_init(struct lm3533 *lm3533)
0382 {
0383     struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
0384     int ret;
0385 
0386     if (!pdata->als)
0387         return 0;
0388 
0389     lm3533_als_devs[0].platform_data = pdata->als;
0390     lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
0391 
0392     ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,
0393                   0, NULL);
0394     if (ret) {
0395         dev_err(lm3533->dev, "failed to add ALS device\n");
0396         return ret;
0397     }
0398 
0399     lm3533->have_als = 1;
0400 
0401     return 0;
0402 }
0403 
0404 static int lm3533_device_bl_init(struct lm3533 *lm3533)
0405 {
0406     struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
0407     int i;
0408     int ret;
0409 
0410     if (!pdata->backlights || pdata->num_backlights == 0)
0411         return 0;
0412 
0413     if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
0414         pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
0415 
0416     for (i = 0; i < pdata->num_backlights; ++i) {
0417         lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
0418         lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
0419     }
0420 
0421     ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
0422                   pdata->num_backlights, NULL, 0, NULL);
0423     if (ret) {
0424         dev_err(lm3533->dev, "failed to add backlight devices\n");
0425         return ret;
0426     }
0427 
0428     lm3533->have_backlights = 1;
0429 
0430     return 0;
0431 }
0432 
0433 static int lm3533_device_led_init(struct lm3533 *lm3533)
0434 {
0435     struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
0436     int i;
0437     int ret;
0438 
0439     if (!pdata->leds || pdata->num_leds == 0)
0440         return 0;
0441 
0442     if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
0443         pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
0444 
0445     for (i = 0; i < pdata->num_leds; ++i) {
0446         lm3533_led_devs[i].platform_data = &pdata->leds[i];
0447         lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
0448     }
0449 
0450     ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
0451                   pdata->num_leds, NULL, 0, NULL);
0452     if (ret) {
0453         dev_err(lm3533->dev, "failed to add LED devices\n");
0454         return ret;
0455     }
0456 
0457     lm3533->have_leds = 1;
0458 
0459     return 0;
0460 }
0461 
0462 static int lm3533_device_setup(struct lm3533 *lm3533,
0463                     struct lm3533_platform_data *pdata)
0464 {
0465     int ret;
0466 
0467     ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);
0468     if (ret)
0469         return ret;
0470 
0471     return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);
0472 }
0473 
0474 static int lm3533_device_init(struct lm3533 *lm3533)
0475 {
0476     struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
0477     int ret;
0478 
0479     dev_dbg(lm3533->dev, "%s\n", __func__);
0480 
0481     if (!pdata) {
0482         dev_err(lm3533->dev, "no platform data\n");
0483         return -EINVAL;
0484     }
0485 
0486     lm3533->gpio_hwen = pdata->gpio_hwen;
0487 
0488     dev_set_drvdata(lm3533->dev, lm3533);
0489 
0490     if (gpio_is_valid(lm3533->gpio_hwen)) {
0491         ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen,
0492                     GPIOF_OUT_INIT_LOW, "lm3533-hwen");
0493         if (ret < 0) {
0494             dev_err(lm3533->dev,
0495                 "failed to request HWEN GPIO %d\n",
0496                 lm3533->gpio_hwen);
0497             return ret;
0498         }
0499     }
0500 
0501     lm3533_enable(lm3533);
0502 
0503     ret = lm3533_device_setup(lm3533, pdata);
0504     if (ret)
0505         goto err_disable;
0506 
0507     lm3533_device_als_init(lm3533);
0508     lm3533_device_bl_init(lm3533);
0509     lm3533_device_led_init(lm3533);
0510 
0511     ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
0512     if (ret < 0) {
0513         dev_err(lm3533->dev, "failed to create sysfs attributes\n");
0514         goto err_unregister;
0515     }
0516 
0517     return 0;
0518 
0519 err_unregister:
0520     mfd_remove_devices(lm3533->dev);
0521 err_disable:
0522     lm3533_disable(lm3533);
0523 
0524     return ret;
0525 }
0526 
0527 static void lm3533_device_exit(struct lm3533 *lm3533)
0528 {
0529     dev_dbg(lm3533->dev, "%s\n", __func__);
0530 
0531     sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
0532 
0533     mfd_remove_devices(lm3533->dev);
0534     lm3533_disable(lm3533);
0535 }
0536 
0537 static bool lm3533_readable_register(struct device *dev, unsigned int reg)
0538 {
0539     switch (reg) {
0540     case 0x10 ... 0x2c:
0541     case 0x30 ... 0x38:
0542     case 0x40 ... 0x45:
0543     case 0x50 ... 0x57:
0544     case 0x60 ... 0x6e:
0545     case 0x70 ... 0x75:
0546     case 0x80 ... 0x85:
0547     case 0x90 ... 0x95:
0548     case 0xa0 ... 0xa5:
0549     case 0xb0 ... 0xb2:
0550         return true;
0551     default:
0552         return false;
0553     }
0554 }
0555 
0556 static bool lm3533_volatile_register(struct device *dev, unsigned int reg)
0557 {
0558     switch (reg) {
0559     case 0x34 ... 0x36: /* zone */
0560     case 0x37 ... 0x38: /* adc */
0561     case 0xb0 ... 0xb1: /* fault */
0562         return true;
0563     default:
0564         return false;
0565     }
0566 }
0567 
0568 static bool lm3533_precious_register(struct device *dev, unsigned int reg)
0569 {
0570     switch (reg) {
0571     case 0x34:      /* zone */
0572         return true;
0573     default:
0574         return false;
0575     }
0576 }
0577 
0578 static const struct regmap_config regmap_config = {
0579     .reg_bits   = 8,
0580     .val_bits   = 8,
0581     .max_register   = LM3533_REG_MAX,
0582     .readable_reg   = lm3533_readable_register,
0583     .volatile_reg   = lm3533_volatile_register,
0584     .precious_reg   = lm3533_precious_register,
0585 };
0586 
0587 static int lm3533_i2c_probe(struct i2c_client *i2c,
0588                     const struct i2c_device_id *id)
0589 {
0590     struct lm3533 *lm3533;
0591 
0592     dev_dbg(&i2c->dev, "%s\n", __func__);
0593 
0594     lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL);
0595     if (!lm3533)
0596         return -ENOMEM;
0597 
0598     i2c_set_clientdata(i2c, lm3533);
0599 
0600     lm3533->regmap = devm_regmap_init_i2c(i2c, &regmap_config);
0601     if (IS_ERR(lm3533->regmap))
0602         return PTR_ERR(lm3533->regmap);
0603 
0604     lm3533->dev = &i2c->dev;
0605     lm3533->irq = i2c->irq;
0606 
0607     return lm3533_device_init(lm3533);
0608 }
0609 
0610 static int lm3533_i2c_remove(struct i2c_client *i2c)
0611 {
0612     struct lm3533 *lm3533 = i2c_get_clientdata(i2c);
0613 
0614     dev_dbg(&i2c->dev, "%s\n", __func__);
0615 
0616     lm3533_device_exit(lm3533);
0617 
0618     return 0;
0619 }
0620 
0621 static const struct i2c_device_id lm3533_i2c_ids[] = {
0622     { "lm3533", 0 },
0623     { },
0624 };
0625 MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
0626 
0627 static struct i2c_driver lm3533_i2c_driver = {
0628     .driver = {
0629            .name = "lm3533",
0630     },
0631     .id_table   = lm3533_i2c_ids,
0632     .probe      = lm3533_i2c_probe,
0633     .remove     = lm3533_i2c_remove,
0634 };
0635 
0636 static int __init lm3533_i2c_init(void)
0637 {
0638     return i2c_add_driver(&lm3533_i2c_driver);
0639 }
0640 subsys_initcall(lm3533_i2c_init);
0641 
0642 static void __exit lm3533_i2c_exit(void)
0643 {
0644     i2c_del_driver(&lm3533_i2c_driver);
0645 }
0646 module_exit(lm3533_i2c_exit);
0647 
0648 MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
0649 MODULE_DESCRIPTION("LM3533 Core");
0650 MODULE_LICENSE("GPL");