116c5c023SJohan Hovold /* 216c5c023SJohan Hovold * lm3533-core.c -- LM3533 Core 316c5c023SJohan Hovold * 416c5c023SJohan Hovold * Copyright (C) 2011-2012 Texas Instruments 516c5c023SJohan Hovold * 616c5c023SJohan Hovold * Author: Johan Hovold <jhovold@gmail.com> 716c5c023SJohan Hovold * 816c5c023SJohan Hovold * This program is free software; you can redistribute it and/or modify it 916c5c023SJohan Hovold * under the terms of the GNU General Public License as published by the 1016c5c023SJohan Hovold * Free Software Foundation; either version 2 of the License, or (at your 1116c5c023SJohan Hovold * option) any later version. 1216c5c023SJohan Hovold */ 1316c5c023SJohan Hovold 1416c5c023SJohan Hovold #include <linux/module.h> 1516c5c023SJohan Hovold #include <linux/init.h> 1616c5c023SJohan Hovold #include <linux/kernel.h> 1716c5c023SJohan Hovold #include <linux/err.h> 1816c5c023SJohan Hovold #include <linux/gpio.h> 1916c5c023SJohan Hovold #include <linux/i2c.h> 2016c5c023SJohan Hovold #include <linux/mfd/core.h> 2116c5c023SJohan Hovold #include <linux/regmap.h> 2216c5c023SJohan Hovold #include <linux/seq_file.h> 2316c5c023SJohan Hovold #include <linux/slab.h> 2416c5c023SJohan Hovold #include <linux/uaccess.h> 2516c5c023SJohan Hovold 2616c5c023SJohan Hovold #include <linux/mfd/lm3533.h> 2716c5c023SJohan Hovold 2816c5c023SJohan Hovold 2916c5c023SJohan Hovold #define LM3533_BOOST_OVP_MASK 0x06 3016c5c023SJohan Hovold #define LM3533_BOOST_OVP_SHIFT 1 3116c5c023SJohan Hovold 3216c5c023SJohan Hovold #define LM3533_BOOST_FREQ_MASK 0x01 3316c5c023SJohan Hovold #define LM3533_BOOST_FREQ_SHIFT 0 3416c5c023SJohan Hovold 3516c5c023SJohan Hovold #define LM3533_BL_ID_MASK 1 3616c5c023SJohan Hovold #define LM3533_LED_ID_MASK 3 3716c5c023SJohan Hovold #define LM3533_BL_ID_MAX 1 3816c5c023SJohan Hovold #define LM3533_LED_ID_MAX 3 3916c5c023SJohan Hovold 4016c5c023SJohan Hovold #define LM3533_HVLED_ID_MAX 2 4116c5c023SJohan Hovold #define LM3533_LVLED_ID_MAX 5 4216c5c023SJohan Hovold 4316c5c023SJohan Hovold #define LM3533_REG_OUTPUT_CONF1 0x10 4416c5c023SJohan Hovold #define LM3533_REG_OUTPUT_CONF2 0x11 4516c5c023SJohan Hovold #define LM3533_REG_BOOST_PWM 0x2c 4616c5c023SJohan Hovold 4716c5c023SJohan Hovold #define LM3533_REG_MAX 0xb2 4816c5c023SJohan Hovold 4916c5c023SJohan Hovold 5016c5c023SJohan Hovold static struct mfd_cell lm3533_als_devs[] = { 5116c5c023SJohan Hovold { 5216c5c023SJohan Hovold .name = "lm3533-als", 5316c5c023SJohan Hovold .id = -1, 5416c5c023SJohan Hovold }, 5516c5c023SJohan Hovold }; 5616c5c023SJohan Hovold 5716c5c023SJohan Hovold static struct mfd_cell lm3533_bl_devs[] = { 5816c5c023SJohan Hovold { 5916c5c023SJohan Hovold .name = "lm3533-backlight", 6016c5c023SJohan Hovold .id = 0, 6116c5c023SJohan Hovold }, 6216c5c023SJohan Hovold { 6316c5c023SJohan Hovold .name = "lm3533-backlight", 6416c5c023SJohan Hovold .id = 1, 6516c5c023SJohan Hovold }, 6616c5c023SJohan Hovold }; 6716c5c023SJohan Hovold 6816c5c023SJohan Hovold static struct mfd_cell lm3533_led_devs[] = { 6916c5c023SJohan Hovold { 7016c5c023SJohan Hovold .name = "lm3533-leds", 7116c5c023SJohan Hovold .id = 0, 7216c5c023SJohan Hovold }, 7316c5c023SJohan Hovold { 7416c5c023SJohan Hovold .name = "lm3533-leds", 7516c5c023SJohan Hovold .id = 1, 7616c5c023SJohan Hovold }, 7716c5c023SJohan Hovold { 7816c5c023SJohan Hovold .name = "lm3533-leds", 7916c5c023SJohan Hovold .id = 2, 8016c5c023SJohan Hovold }, 8116c5c023SJohan Hovold { 8216c5c023SJohan Hovold .name = "lm3533-leds", 8316c5c023SJohan Hovold .id = 3, 8416c5c023SJohan Hovold }, 8516c5c023SJohan Hovold }; 8616c5c023SJohan Hovold 8716c5c023SJohan Hovold int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val) 8816c5c023SJohan Hovold { 8916c5c023SJohan Hovold int tmp; 9016c5c023SJohan Hovold int ret; 9116c5c023SJohan Hovold 9216c5c023SJohan Hovold ret = regmap_read(lm3533->regmap, reg, &tmp); 9316c5c023SJohan Hovold if (ret < 0) { 9416c5c023SJohan Hovold dev_err(lm3533->dev, "failed to read register %02x: %d\n", 9516c5c023SJohan Hovold reg, ret); 9616c5c023SJohan Hovold return ret; 9716c5c023SJohan Hovold } 9816c5c023SJohan Hovold 9916c5c023SJohan Hovold *val = tmp; 10016c5c023SJohan Hovold 10116c5c023SJohan Hovold dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val); 10216c5c023SJohan Hovold 10316c5c023SJohan Hovold return ret; 10416c5c023SJohan Hovold } 10516c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_read); 10616c5c023SJohan Hovold 10716c5c023SJohan Hovold int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val) 10816c5c023SJohan Hovold { 10916c5c023SJohan Hovold int ret; 11016c5c023SJohan Hovold 11116c5c023SJohan Hovold dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val); 11216c5c023SJohan Hovold 11316c5c023SJohan Hovold ret = regmap_write(lm3533->regmap, reg, val); 11416c5c023SJohan Hovold if (ret < 0) { 11516c5c023SJohan Hovold dev_err(lm3533->dev, "failed to write register %02x: %d\n", 11616c5c023SJohan Hovold reg, ret); 11716c5c023SJohan Hovold } 11816c5c023SJohan Hovold 11916c5c023SJohan Hovold return ret; 12016c5c023SJohan Hovold } 12116c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_write); 12216c5c023SJohan Hovold 12316c5c023SJohan Hovold int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask) 12416c5c023SJohan Hovold { 12516c5c023SJohan Hovold int ret; 12616c5c023SJohan Hovold 12716c5c023SJohan Hovold dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask); 12816c5c023SJohan Hovold 129664dd066SAxel Lin ret = regmap_update_bits(lm3533->regmap, reg, mask, val); 13016c5c023SJohan Hovold if (ret < 0) { 13116c5c023SJohan Hovold dev_err(lm3533->dev, "failed to update register %02x: %d\n", 13216c5c023SJohan Hovold reg, ret); 13316c5c023SJohan Hovold } 13416c5c023SJohan Hovold 13516c5c023SJohan Hovold return ret; 13616c5c023SJohan Hovold } 13716c5c023SJohan Hovold EXPORT_SYMBOL_GPL(lm3533_update); 13816c5c023SJohan Hovold 139d9055dc5SJohan Hovold static int lm3533_set_boost_freq(struct lm3533 *lm3533, 140d9055dc5SJohan Hovold enum lm3533_boost_freq freq) 141d9055dc5SJohan Hovold { 142d9055dc5SJohan Hovold int ret; 143d9055dc5SJohan Hovold 144d9055dc5SJohan Hovold ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM, 145d9055dc5SJohan Hovold freq << LM3533_BOOST_FREQ_SHIFT, 146d9055dc5SJohan Hovold LM3533_BOOST_FREQ_MASK); 147d9055dc5SJohan Hovold if (ret) 148d9055dc5SJohan Hovold dev_err(lm3533->dev, "failed to set boost frequency\n"); 149d9055dc5SJohan Hovold 150d9055dc5SJohan Hovold return ret; 151d9055dc5SJohan Hovold } 152d9055dc5SJohan Hovold 153d9055dc5SJohan Hovold 154d9055dc5SJohan Hovold static int lm3533_set_boost_ovp(struct lm3533 *lm3533, 155d9055dc5SJohan Hovold enum lm3533_boost_ovp ovp) 156d9055dc5SJohan Hovold { 157d9055dc5SJohan Hovold int ret; 158d9055dc5SJohan Hovold 159d9055dc5SJohan Hovold ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM, 160d9055dc5SJohan Hovold ovp << LM3533_BOOST_OVP_SHIFT, 161d9055dc5SJohan Hovold LM3533_BOOST_OVP_MASK); 162d9055dc5SJohan Hovold if (ret) 163d9055dc5SJohan Hovold dev_err(lm3533->dev, "failed to set boost ovp\n"); 164d9055dc5SJohan Hovold 165d9055dc5SJohan Hovold return ret; 166d9055dc5SJohan Hovold } 167d9055dc5SJohan Hovold 16816c5c023SJohan Hovold /* 16916c5c023SJohan Hovold * HVLED output config -- output hvled controlled by backlight bl 17016c5c023SJohan Hovold */ 17116c5c023SJohan Hovold static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl) 17216c5c023SJohan Hovold { 17316c5c023SJohan Hovold u8 val; 17416c5c023SJohan Hovold u8 mask; 17516c5c023SJohan Hovold int shift; 17616c5c023SJohan Hovold int ret; 17716c5c023SJohan Hovold 17816c5c023SJohan Hovold if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX) 17916c5c023SJohan Hovold return -EINVAL; 18016c5c023SJohan Hovold 18116c5c023SJohan Hovold if (bl > LM3533_BL_ID_MAX) 18216c5c023SJohan Hovold return -EINVAL; 18316c5c023SJohan Hovold 18416c5c023SJohan Hovold shift = hvled - 1; 18516c5c023SJohan Hovold mask = LM3533_BL_ID_MASK << shift; 18616c5c023SJohan Hovold val = bl << shift; 18716c5c023SJohan Hovold 18816c5c023SJohan Hovold ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask); 18916c5c023SJohan Hovold if (ret) 19016c5c023SJohan Hovold dev_err(lm3533->dev, "failed to set hvled config\n"); 19116c5c023SJohan Hovold 19216c5c023SJohan Hovold return ret; 19316c5c023SJohan Hovold } 19416c5c023SJohan Hovold 19516c5c023SJohan Hovold /* 19616c5c023SJohan Hovold * LVLED output config -- output lvled controlled by LED led 19716c5c023SJohan Hovold */ 19816c5c023SJohan Hovold static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led) 19916c5c023SJohan Hovold { 20016c5c023SJohan Hovold u8 reg; 20116c5c023SJohan Hovold u8 val; 20216c5c023SJohan Hovold u8 mask; 20316c5c023SJohan Hovold int shift; 20416c5c023SJohan Hovold int ret; 20516c5c023SJohan Hovold 20616c5c023SJohan Hovold if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX) 20716c5c023SJohan Hovold return -EINVAL; 20816c5c023SJohan Hovold 20916c5c023SJohan Hovold if (led > LM3533_LED_ID_MAX) 21016c5c023SJohan Hovold return -EINVAL; 21116c5c023SJohan Hovold 21216c5c023SJohan Hovold if (lvled < 4) { 21316c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF1; 21416c5c023SJohan Hovold shift = 2 * lvled; 21516c5c023SJohan Hovold } else { 21616c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF2; 21716c5c023SJohan Hovold shift = 2 * (lvled - 4); 21816c5c023SJohan Hovold } 21916c5c023SJohan Hovold 22016c5c023SJohan Hovold mask = LM3533_LED_ID_MASK << shift; 22116c5c023SJohan Hovold val = led << shift; 22216c5c023SJohan Hovold 22316c5c023SJohan Hovold ret = lm3533_update(lm3533, reg, val, mask); 22416c5c023SJohan Hovold if (ret) 22516c5c023SJohan Hovold dev_err(lm3533->dev, "failed to set lvled config\n"); 22616c5c023SJohan Hovold 22716c5c023SJohan Hovold return ret; 22816c5c023SJohan Hovold } 22916c5c023SJohan Hovold 23016c5c023SJohan Hovold static void lm3533_enable(struct lm3533 *lm3533) 23116c5c023SJohan Hovold { 23216c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen)) 23316c5c023SJohan Hovold gpio_set_value(lm3533->gpio_hwen, 1); 23416c5c023SJohan Hovold } 23516c5c023SJohan Hovold 23616c5c023SJohan Hovold static void lm3533_disable(struct lm3533 *lm3533) 23716c5c023SJohan Hovold { 23816c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen)) 23916c5c023SJohan Hovold gpio_set_value(lm3533->gpio_hwen, 0); 24016c5c023SJohan Hovold } 24116c5c023SJohan Hovold 24216c5c023SJohan Hovold enum lm3533_attribute_type { 24316c5c023SJohan Hovold LM3533_ATTR_TYPE_BACKLIGHT, 24416c5c023SJohan Hovold LM3533_ATTR_TYPE_LED, 24516c5c023SJohan Hovold }; 24616c5c023SJohan Hovold 24716c5c023SJohan Hovold struct lm3533_device_attribute { 24816c5c023SJohan Hovold struct device_attribute dev_attr; 24916c5c023SJohan Hovold enum lm3533_attribute_type type; 25016c5c023SJohan Hovold union { 25116c5c023SJohan Hovold struct { 25216c5c023SJohan Hovold u8 id; 25316c5c023SJohan Hovold } output; 25416c5c023SJohan Hovold } u; 25516c5c023SJohan Hovold }; 25616c5c023SJohan Hovold 25716c5c023SJohan Hovold #define to_lm3533_dev_attr(_attr) \ 25816c5c023SJohan Hovold container_of(_attr, struct lm3533_device_attribute, dev_attr) 25916c5c023SJohan Hovold 26016c5c023SJohan Hovold static ssize_t show_output(struct device *dev, 26116c5c023SJohan Hovold struct device_attribute *attr, char *buf) 26216c5c023SJohan Hovold { 26316c5c023SJohan Hovold struct lm3533 *lm3533 = dev_get_drvdata(dev); 26416c5c023SJohan Hovold struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr); 26516c5c023SJohan Hovold int id = lattr->u.output.id; 26616c5c023SJohan Hovold u8 reg; 26716c5c023SJohan Hovold u8 val; 26816c5c023SJohan Hovold u8 mask; 26916c5c023SJohan Hovold int shift; 27016c5c023SJohan Hovold int ret; 27116c5c023SJohan Hovold 27216c5c023SJohan Hovold if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) { 27316c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF1; 27416c5c023SJohan Hovold shift = id - 1; 27516c5c023SJohan Hovold mask = LM3533_BL_ID_MASK << shift; 27616c5c023SJohan Hovold } else { 27716c5c023SJohan Hovold if (id < 4) { 27816c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF1; 27916c5c023SJohan Hovold shift = 2 * id; 28016c5c023SJohan Hovold } else { 28116c5c023SJohan Hovold reg = LM3533_REG_OUTPUT_CONF2; 28216c5c023SJohan Hovold shift = 2 * (id - 4); 28316c5c023SJohan Hovold } 28416c5c023SJohan Hovold mask = LM3533_LED_ID_MASK << shift; 28516c5c023SJohan Hovold } 28616c5c023SJohan Hovold 28716c5c023SJohan Hovold ret = lm3533_read(lm3533, reg, &val); 28816c5c023SJohan Hovold if (ret) 28916c5c023SJohan Hovold return ret; 29016c5c023SJohan Hovold 29116c5c023SJohan Hovold val = (val & mask) >> shift; 29216c5c023SJohan Hovold 29316c5c023SJohan Hovold return scnprintf(buf, PAGE_SIZE, "%u\n", val); 29416c5c023SJohan Hovold } 29516c5c023SJohan Hovold 29616c5c023SJohan Hovold static ssize_t store_output(struct device *dev, 29716c5c023SJohan Hovold struct device_attribute *attr, 29816c5c023SJohan Hovold const char *buf, size_t len) 29916c5c023SJohan Hovold { 30016c5c023SJohan Hovold struct lm3533 *lm3533 = dev_get_drvdata(dev); 30116c5c023SJohan Hovold struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr); 30216c5c023SJohan Hovold int id = lattr->u.output.id; 30316c5c023SJohan Hovold u8 val; 30416c5c023SJohan Hovold int ret; 30516c5c023SJohan Hovold 30616c5c023SJohan Hovold if (kstrtou8(buf, 0, &val)) 30716c5c023SJohan Hovold return -EINVAL; 30816c5c023SJohan Hovold 30916c5c023SJohan Hovold if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) 31016c5c023SJohan Hovold ret = lm3533_set_hvled_config(lm3533, id, val); 31116c5c023SJohan Hovold else 31216c5c023SJohan Hovold ret = lm3533_set_lvled_config(lm3533, id, val); 31316c5c023SJohan Hovold 31416c5c023SJohan Hovold if (ret) 31516c5c023SJohan Hovold return ret; 31616c5c023SJohan Hovold 31716c5c023SJohan Hovold return len; 31816c5c023SJohan Hovold } 31916c5c023SJohan Hovold 32016c5c023SJohan Hovold #define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \ 32116c5c023SJohan Hovold struct lm3533_device_attribute lm3533_dev_attr_##_name = \ 32216c5c023SJohan Hovold { .dev_attr = __ATTR(_name, _mode, _show, _store), \ 32316c5c023SJohan Hovold .type = _type, \ 32416c5c023SJohan Hovold .u.output = { .id = _id }, } 32516c5c023SJohan Hovold 32616c5c023SJohan Hovold #define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \ 32716c5c023SJohan Hovold LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \ 32816c5c023SJohan Hovold show_output, store_output, _type, _id) 32916c5c023SJohan Hovold 33016c5c023SJohan Hovold #define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \ 33116c5c023SJohan Hovold LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr) 33216c5c023SJohan Hovold #define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \ 33316c5c023SJohan Hovold LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr) 33416c5c023SJohan Hovold /* 33516c5c023SJohan Hovold * Output config: 33616c5c023SJohan Hovold * 33716c5c023SJohan Hovold * output_hvled<nr> 0-1 33816c5c023SJohan Hovold * output_lvled<nr> 0-3 33916c5c023SJohan Hovold */ 34016c5c023SJohan Hovold static LM3533_OUTPUT_HVLED_ATTR_RW(1); 34116c5c023SJohan Hovold static LM3533_OUTPUT_HVLED_ATTR_RW(2); 34216c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(1); 34316c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(2); 34416c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(3); 34516c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(4); 34616c5c023SJohan Hovold static LM3533_OUTPUT_LVLED_ATTR_RW(5); 34716c5c023SJohan Hovold 34816c5c023SJohan Hovold static struct attribute *lm3533_attributes[] = { 34916c5c023SJohan Hovold &lm3533_dev_attr_output_hvled1.dev_attr.attr, 35016c5c023SJohan Hovold &lm3533_dev_attr_output_hvled2.dev_attr.attr, 35116c5c023SJohan Hovold &lm3533_dev_attr_output_lvled1.dev_attr.attr, 35216c5c023SJohan Hovold &lm3533_dev_attr_output_lvled2.dev_attr.attr, 35316c5c023SJohan Hovold &lm3533_dev_attr_output_lvled3.dev_attr.attr, 35416c5c023SJohan Hovold &lm3533_dev_attr_output_lvled4.dev_attr.attr, 35516c5c023SJohan Hovold &lm3533_dev_attr_output_lvled5.dev_attr.attr, 35616c5c023SJohan Hovold NULL, 35716c5c023SJohan Hovold }; 35816c5c023SJohan Hovold 35916c5c023SJohan Hovold #define to_dev_attr(_attr) \ 36016c5c023SJohan Hovold container_of(_attr, struct device_attribute, attr) 36116c5c023SJohan Hovold 362168755ebSDan Carpenter static umode_t lm3533_attr_is_visible(struct kobject *kobj, 36316c5c023SJohan Hovold struct attribute *attr, int n) 36416c5c023SJohan Hovold { 36516c5c023SJohan Hovold struct device *dev = container_of(kobj, struct device, kobj); 36616c5c023SJohan Hovold struct lm3533 *lm3533 = dev_get_drvdata(dev); 36716c5c023SJohan Hovold struct device_attribute *dattr = to_dev_attr(attr); 36816c5c023SJohan Hovold struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr); 36916c5c023SJohan Hovold enum lm3533_attribute_type type = lattr->type; 37060908855SJohan Hovold umode_t mode = attr->mode; 37116c5c023SJohan Hovold 37216c5c023SJohan Hovold if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT) 37316c5c023SJohan Hovold mode = 0; 37416c5c023SJohan Hovold else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED) 37516c5c023SJohan Hovold mode = 0; 37616c5c023SJohan Hovold 37716c5c023SJohan Hovold return mode; 37816c5c023SJohan Hovold }; 37916c5c023SJohan Hovold 38016c5c023SJohan Hovold static struct attribute_group lm3533_attribute_group = { 38116c5c023SJohan Hovold .is_visible = lm3533_attr_is_visible, 38216c5c023SJohan Hovold .attrs = lm3533_attributes 38316c5c023SJohan Hovold }; 38416c5c023SJohan Hovold 38516c5c023SJohan Hovold static int __devinit lm3533_device_als_init(struct lm3533 *lm3533) 38616c5c023SJohan Hovold { 38716c5c023SJohan Hovold struct lm3533_platform_data *pdata = lm3533->dev->platform_data; 38816c5c023SJohan Hovold int ret; 38916c5c023SJohan Hovold 39016c5c023SJohan Hovold if (!pdata->als) 39116c5c023SJohan Hovold return 0; 39216c5c023SJohan Hovold 39316c5c023SJohan Hovold lm3533_als_devs[0].platform_data = pdata->als; 39416c5c023SJohan Hovold lm3533_als_devs[0].pdata_size = sizeof(*pdata->als); 39516c5c023SJohan Hovold 3960848c94fSMark Brown ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, 3970848c94fSMark Brown 0, NULL); 39816c5c023SJohan Hovold if (ret) { 39916c5c023SJohan Hovold dev_err(lm3533->dev, "failed to add ALS device\n"); 40016c5c023SJohan Hovold return ret; 40116c5c023SJohan Hovold } 40216c5c023SJohan Hovold 40316c5c023SJohan Hovold lm3533->have_als = 1; 40416c5c023SJohan Hovold 40516c5c023SJohan Hovold return 0; 40616c5c023SJohan Hovold } 40716c5c023SJohan Hovold 40816c5c023SJohan Hovold static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533) 40916c5c023SJohan Hovold { 41016c5c023SJohan Hovold struct lm3533_platform_data *pdata = lm3533->dev->platform_data; 41116c5c023SJohan Hovold int i; 41216c5c023SJohan Hovold int ret; 41316c5c023SJohan Hovold 41416c5c023SJohan Hovold if (!pdata->backlights || pdata->num_backlights == 0) 41516c5c023SJohan Hovold return 0; 41616c5c023SJohan Hovold 41716c5c023SJohan Hovold if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs)) 41816c5c023SJohan Hovold pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs); 41916c5c023SJohan Hovold 42016c5c023SJohan Hovold for (i = 0; i < pdata->num_backlights; ++i) { 42116c5c023SJohan Hovold lm3533_bl_devs[i].platform_data = &pdata->backlights[i]; 42216c5c023SJohan Hovold lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]); 42316c5c023SJohan Hovold } 42416c5c023SJohan Hovold 42516c5c023SJohan Hovold ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs, 4260848c94fSMark Brown pdata->num_backlights, NULL, 0, NULL); 42716c5c023SJohan Hovold if (ret) { 42816c5c023SJohan Hovold dev_err(lm3533->dev, "failed to add backlight devices\n"); 42916c5c023SJohan Hovold return ret; 43016c5c023SJohan Hovold } 43116c5c023SJohan Hovold 43216c5c023SJohan Hovold lm3533->have_backlights = 1; 43316c5c023SJohan Hovold 43416c5c023SJohan Hovold return 0; 43516c5c023SJohan Hovold } 43616c5c023SJohan Hovold 43716c5c023SJohan Hovold static int __devinit lm3533_device_led_init(struct lm3533 *lm3533) 43816c5c023SJohan Hovold { 43916c5c023SJohan Hovold struct lm3533_platform_data *pdata = lm3533->dev->platform_data; 44016c5c023SJohan Hovold int i; 44116c5c023SJohan Hovold int ret; 44216c5c023SJohan Hovold 44316c5c023SJohan Hovold if (!pdata->leds || pdata->num_leds == 0) 44416c5c023SJohan Hovold return 0; 44516c5c023SJohan Hovold 44616c5c023SJohan Hovold if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs)) 44716c5c023SJohan Hovold pdata->num_leds = ARRAY_SIZE(lm3533_led_devs); 44816c5c023SJohan Hovold 44916c5c023SJohan Hovold for (i = 0; i < pdata->num_leds; ++i) { 45016c5c023SJohan Hovold lm3533_led_devs[i].platform_data = &pdata->leds[i]; 45116c5c023SJohan Hovold lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]); 45216c5c023SJohan Hovold } 45316c5c023SJohan Hovold 45416c5c023SJohan Hovold ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs, 4550848c94fSMark Brown pdata->num_leds, NULL, 0, NULL); 45616c5c023SJohan Hovold if (ret) { 45716c5c023SJohan Hovold dev_err(lm3533->dev, "failed to add LED devices\n"); 45816c5c023SJohan Hovold return ret; 45916c5c023SJohan Hovold } 46016c5c023SJohan Hovold 46116c5c023SJohan Hovold lm3533->have_leds = 1; 46216c5c023SJohan Hovold 46316c5c023SJohan Hovold return 0; 46416c5c023SJohan Hovold } 46516c5c023SJohan Hovold 466d9055dc5SJohan Hovold static int __devinit lm3533_device_setup(struct lm3533 *lm3533, 467d9055dc5SJohan Hovold struct lm3533_platform_data *pdata) 468d9055dc5SJohan Hovold { 469d9055dc5SJohan Hovold int ret; 470d9055dc5SJohan Hovold 471d9055dc5SJohan Hovold ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq); 472d9055dc5SJohan Hovold if (ret) 473d9055dc5SJohan Hovold return ret; 474d9055dc5SJohan Hovold 475d9055dc5SJohan Hovold ret = lm3533_set_boost_ovp(lm3533, pdata->boost_ovp); 476d9055dc5SJohan Hovold if (ret) 477d9055dc5SJohan Hovold return ret; 478d9055dc5SJohan Hovold 479d9055dc5SJohan Hovold return 0; 480d9055dc5SJohan Hovold } 481d9055dc5SJohan Hovold 48216c5c023SJohan Hovold static int __devinit lm3533_device_init(struct lm3533 *lm3533) 48316c5c023SJohan Hovold { 48416c5c023SJohan Hovold struct lm3533_platform_data *pdata = lm3533->dev->platform_data; 48516c5c023SJohan Hovold int ret; 48616c5c023SJohan Hovold 48716c5c023SJohan Hovold dev_dbg(lm3533->dev, "%s\n", __func__); 48816c5c023SJohan Hovold 48916c5c023SJohan Hovold if (!pdata) { 49016c5c023SJohan Hovold dev_err(lm3533->dev, "no platform data\n"); 49116c5c023SJohan Hovold return -EINVAL; 49216c5c023SJohan Hovold } 49316c5c023SJohan Hovold 49416c5c023SJohan Hovold lm3533->gpio_hwen = pdata->gpio_hwen; 49516c5c023SJohan Hovold 49616c5c023SJohan Hovold dev_set_drvdata(lm3533->dev, lm3533); 49716c5c023SJohan Hovold 49816c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen)) { 49916c5c023SJohan Hovold ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW, 50016c5c023SJohan Hovold "lm3533-hwen"); 50116c5c023SJohan Hovold if (ret < 0) { 50216c5c023SJohan Hovold dev_err(lm3533->dev, 50316c5c023SJohan Hovold "failed to request HWEN GPIO %d\n", 50416c5c023SJohan Hovold lm3533->gpio_hwen); 50516c5c023SJohan Hovold return ret; 50616c5c023SJohan Hovold } 50716c5c023SJohan Hovold } 50816c5c023SJohan Hovold 50916c5c023SJohan Hovold lm3533_enable(lm3533); 51016c5c023SJohan Hovold 511d9055dc5SJohan Hovold ret = lm3533_device_setup(lm3533, pdata); 512d9055dc5SJohan Hovold if (ret) 513d9055dc5SJohan Hovold goto err_disable; 514d9055dc5SJohan Hovold 51516c5c023SJohan Hovold lm3533_device_als_init(lm3533); 51616c5c023SJohan Hovold lm3533_device_bl_init(lm3533); 51716c5c023SJohan Hovold lm3533_device_led_init(lm3533); 51816c5c023SJohan Hovold 51916c5c023SJohan Hovold ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group); 52016c5c023SJohan Hovold if (ret < 0) { 52116c5c023SJohan Hovold dev_err(lm3533->dev, "failed to create sysfs attributes\n"); 52216c5c023SJohan Hovold goto err_unregister; 52316c5c023SJohan Hovold } 52416c5c023SJohan Hovold 52516c5c023SJohan Hovold return 0; 52616c5c023SJohan Hovold 52716c5c023SJohan Hovold err_unregister: 52816c5c023SJohan Hovold mfd_remove_devices(lm3533->dev); 529d9055dc5SJohan Hovold err_disable: 53016c5c023SJohan Hovold lm3533_disable(lm3533); 53116c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen)) 53216c5c023SJohan Hovold gpio_free(lm3533->gpio_hwen); 53316c5c023SJohan Hovold 53416c5c023SJohan Hovold return ret; 53516c5c023SJohan Hovold } 53616c5c023SJohan Hovold 53716c5c023SJohan Hovold static void __devexit lm3533_device_exit(struct lm3533 *lm3533) 53816c5c023SJohan Hovold { 53916c5c023SJohan Hovold dev_dbg(lm3533->dev, "%s\n", __func__); 54016c5c023SJohan Hovold 54116c5c023SJohan Hovold sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group); 54216c5c023SJohan Hovold 54316c5c023SJohan Hovold mfd_remove_devices(lm3533->dev); 54416c5c023SJohan Hovold lm3533_disable(lm3533); 54516c5c023SJohan Hovold if (gpio_is_valid(lm3533->gpio_hwen)) 54616c5c023SJohan Hovold gpio_free(lm3533->gpio_hwen); 54716c5c023SJohan Hovold } 54816c5c023SJohan Hovold 54916c5c023SJohan Hovold static bool lm3533_readable_register(struct device *dev, unsigned int reg) 55016c5c023SJohan Hovold { 55116c5c023SJohan Hovold switch (reg) { 55216c5c023SJohan Hovold case 0x10 ... 0x2c: 55316c5c023SJohan Hovold case 0x30 ... 0x38: 55416c5c023SJohan Hovold case 0x40 ... 0x45: 55516c5c023SJohan Hovold case 0x50 ... 0x57: 55616c5c023SJohan Hovold case 0x60 ... 0x6e: 55716c5c023SJohan Hovold case 0x70 ... 0x75: 55816c5c023SJohan Hovold case 0x80 ... 0x85: 55916c5c023SJohan Hovold case 0x90 ... 0x95: 56016c5c023SJohan Hovold case 0xa0 ... 0xa5: 56116c5c023SJohan Hovold case 0xb0 ... 0xb2: 56216c5c023SJohan Hovold return true; 56316c5c023SJohan Hovold default: 56416c5c023SJohan Hovold return false; 56516c5c023SJohan Hovold } 56616c5c023SJohan Hovold } 56716c5c023SJohan Hovold 56816c5c023SJohan Hovold static bool lm3533_volatile_register(struct device *dev, unsigned int reg) 56916c5c023SJohan Hovold { 57016c5c023SJohan Hovold switch (reg) { 571c48bf153SJohan Hovold case 0x34 ... 0x36: /* zone */ 57216c5c023SJohan Hovold case 0x37 ... 0x38: /* adc */ 57316c5c023SJohan Hovold case 0xb0 ... 0xb1: /* fault */ 57416c5c023SJohan Hovold return true; 57516c5c023SJohan Hovold default: 57616c5c023SJohan Hovold return false; 57716c5c023SJohan Hovold } 57816c5c023SJohan Hovold } 57916c5c023SJohan Hovold 58016c5c023SJohan Hovold static bool lm3533_precious_register(struct device *dev, unsigned int reg) 58116c5c023SJohan Hovold { 58216c5c023SJohan Hovold switch (reg) { 58316c5c023SJohan Hovold case 0x34: /* zone */ 58416c5c023SJohan Hovold return true; 58516c5c023SJohan Hovold default: 58616c5c023SJohan Hovold return false; 58716c5c023SJohan Hovold } 58816c5c023SJohan Hovold } 58916c5c023SJohan Hovold 59016c5c023SJohan Hovold static struct regmap_config regmap_config = { 59116c5c023SJohan Hovold .reg_bits = 8, 59216c5c023SJohan Hovold .val_bits = 8, 59316c5c023SJohan Hovold .max_register = LM3533_REG_MAX, 59416c5c023SJohan Hovold .readable_reg = lm3533_readable_register, 59516c5c023SJohan Hovold .volatile_reg = lm3533_volatile_register, 59616c5c023SJohan Hovold .precious_reg = lm3533_precious_register, 59716c5c023SJohan Hovold }; 59816c5c023SJohan Hovold 59916c5c023SJohan Hovold static int __devinit lm3533_i2c_probe(struct i2c_client *i2c, 60016c5c023SJohan Hovold const struct i2c_device_id *id) 60116c5c023SJohan Hovold { 60216c5c023SJohan Hovold struct lm3533 *lm3533; 60316c5c023SJohan Hovold int ret; 60416c5c023SJohan Hovold 60516c5c023SJohan Hovold dev_dbg(&i2c->dev, "%s\n", __func__); 60616c5c023SJohan Hovold 607fa648e51SJohan Hovold lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL); 60816c5c023SJohan Hovold if (!lm3533) 60916c5c023SJohan Hovold return -ENOMEM; 61016c5c023SJohan Hovold 61116c5c023SJohan Hovold i2c_set_clientdata(i2c, lm3533); 61216c5c023SJohan Hovold 613fa648e51SJohan Hovold lm3533->regmap = devm_regmap_init_i2c(i2c, ®map_config); 614fa648e51SJohan Hovold if (IS_ERR(lm3533->regmap)) 615fa648e51SJohan Hovold return PTR_ERR(lm3533->regmap); 61616c5c023SJohan Hovold 61716c5c023SJohan Hovold lm3533->dev = &i2c->dev; 61816c5c023SJohan Hovold lm3533->irq = i2c->irq; 61916c5c023SJohan Hovold 62016c5c023SJohan Hovold ret = lm3533_device_init(lm3533); 62116c5c023SJohan Hovold if (ret) 622fa648e51SJohan Hovold return ret; 62316c5c023SJohan Hovold 62416c5c023SJohan Hovold return 0; 62516c5c023SJohan Hovold } 62616c5c023SJohan Hovold 62716c5c023SJohan Hovold static int __devexit lm3533_i2c_remove(struct i2c_client *i2c) 62816c5c023SJohan Hovold { 62916c5c023SJohan Hovold struct lm3533 *lm3533 = i2c_get_clientdata(i2c); 63016c5c023SJohan Hovold 63116c5c023SJohan Hovold dev_dbg(&i2c->dev, "%s\n", __func__); 63216c5c023SJohan Hovold 63316c5c023SJohan Hovold lm3533_device_exit(lm3533); 63416c5c023SJohan Hovold 63516c5c023SJohan Hovold return 0; 63616c5c023SJohan Hovold } 63716c5c023SJohan Hovold 63816c5c023SJohan Hovold static const struct i2c_device_id lm3533_i2c_ids[] = { 63916c5c023SJohan Hovold { "lm3533", 0 }, 64016c5c023SJohan Hovold { }, 64116c5c023SJohan Hovold }; 64216c5c023SJohan Hovold MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids); 64316c5c023SJohan Hovold 64416c5c023SJohan Hovold static struct i2c_driver lm3533_i2c_driver = { 64516c5c023SJohan Hovold .driver = { 64616c5c023SJohan Hovold .name = "lm3533", 64716c5c023SJohan Hovold .owner = THIS_MODULE, 64816c5c023SJohan Hovold }, 64916c5c023SJohan Hovold .id_table = lm3533_i2c_ids, 65016c5c023SJohan Hovold .probe = lm3533_i2c_probe, 65116c5c023SJohan Hovold .remove = __devexit_p(lm3533_i2c_remove), 65216c5c023SJohan Hovold }; 65316c5c023SJohan Hovold 65416c5c023SJohan Hovold static int __init lm3533_i2c_init(void) 65516c5c023SJohan Hovold { 65616c5c023SJohan Hovold return i2c_add_driver(&lm3533_i2c_driver); 65716c5c023SJohan Hovold } 65816c5c023SJohan Hovold subsys_initcall(lm3533_i2c_init); 65916c5c023SJohan Hovold 66016c5c023SJohan Hovold static void __exit lm3533_i2c_exit(void) 66116c5c023SJohan Hovold { 66216c5c023SJohan Hovold i2c_del_driver(&lm3533_i2c_driver); 66316c5c023SJohan Hovold } 66416c5c023SJohan Hovold module_exit(lm3533_i2c_exit); 66516c5c023SJohan Hovold 66616c5c023SJohan Hovold MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>"); 66716c5c023SJohan Hovold MODULE_DESCRIPTION("LM3533 Core"); 66816c5c023SJohan Hovold MODULE_LICENSE("GPL"); 669