summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d2f910f)
raw | patch | inline | side by side (parent: d2f910f)
author | Daniel Jeong <gshark.jeong@gmail.com> | |
Thu, 12 Feb 2015 11:29:40 +0000 (20:29 +0900) | ||
committer | Daniel Jeong <gshark.jeong@gmail.com> | |
Thu, 12 Feb 2015 11:29:40 +0000 (20:29 +0900) |
Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>
15 files changed:
diff --git a/Documentation/devicetree/bindings/mfd/lm3631.txt b/Documentation/devicetree/bindings/mfd/lm3631.txt
--- /dev/null
@@ -0,0 +1,59 @@
+TI LM3631 MFD Driver
+
+Required properties:
+ - compatible: "ti,lm3631"
+ - reg: I2C slave address. 0x29.
+ - ti,en-gpio: GPIO number of LM3631 nRST pin.
+
+LM3631 consists of two sub-devices, lm3631-regulator and lm3631-bl.
+
+For the LM3631 regulator properties please refer to:
+Documentation/devicetree/bindings/regulator/lm3631-regulator.txt
+
+For the LM3631 backlight properties please refer to:
+Documentation/devicetree/bindings/video/backlight/lm3631_bl.txt
+
+Example:
+
+lm3631@29 {
+ compatible = "ti,lm3631";
+ reg = <0x29>;
+
+ /* GPIO134 for HWEN pin */
+ ti,en-gpio = <&gpio5 6 0>;
+
+ /* Only Vpos and Vneg are used with LCD boost */
+ regulators {
+ compatible = "ti,lm3631-regulator";
+
+ vboost {
+ regulator-name = "lcd_boost";
+ regulator-min-microvolt = <4500000>;
+ regulator-max-microvolt = <6350000>;
+ regulator-always-on;
+ };
+
+ vpos {
+ regulator-name = "lcd_vpos";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-boot-on;
+ };
+
+ vneg {
+ regulator-name = "lcd_vneg";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-boot-on;
+ };
+ };
+
+ /* Backlight mode is I2C + PWM, two strings used */
+ backlight {
+ compatible = "ti,lm3631-backlight";
+
+ bl-name = "lcd";
+ full-strings-used;
+ mode-comb1;
+ };
+};
diff --git a/Documentation/devicetree/bindings/regulator/lm3631-regulator.txt b/Documentation/devicetree/bindings/regulator/lm3631-regulator.txt
--- /dev/null
@@ -0,0 +1,57 @@
+TI LM3631 Regulator Driver
+
+Required properties:
+ - compatible: "ti,lm3631-regulator"
+ - Regulator init data from of-regulator structure.
+ Please refer to regulator.txt in this directory.
+
+Example:
+
+&i2c4 {
+ clock-frequency = <400000>;
+
+ lm3631@29 {
+ compatible = "ti,lm3631";
+ reg = <0x29>;
+
+ /* GPIO134 for HWEN pin */
+ ti,en-gpio = <&gpio5 6 0>;
+
+ regulators {
+ compatible = "ti,lm3631-regulator";
+
+ vboost {
+ regulator-name = "lcd_boost";
+ regulator-min-microvolt = <4500000>;
+ regulator-max-microvolt = <6350000>;
+ regulator-always-on;
+ };
+
+ vcont {
+ regulator-name = "lcd_cont";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ voref {
+ regulator-compatible = "voref";
+ regulator-name = "lcd_oref";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ };
+
+ vpos {
+ regulator-name = "lcd_vpos";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-boot-on;
+ };
+
+ vneg {
+ regulator-name = "lcd_vneg";
+ regulator-min-microvolt = <4000000>;
+ regulator-max-microvolt = <6000000>;
+ regulator-boot-on;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/video/backlight/lm3631_bl.txt b/Documentation/devicetree/bindings/video/backlight/lm3631_bl.txt
--- /dev/null
@@ -0,0 +1,65 @@
+TI LM3631 Backlight Driver
+
+Required properties:
+ - compatible: "ti,lm3631-backlight"
+
+Optional properties:
+ - bl-name: Backlight device name
+ - full-strings-used: Define it in case of two LED strings used.
+ - mode-pwm-only: PWM input mode
+ or mode-comb1: I2C x PWM befoer sloping
+ or mode-comb2: Sloped I2C x PWM
+ The default mode is the I2C only.
+ - initial-brightness: Initial brightness value
+
+PWM specific optional properties:
+ - pwm-period: PWM period value. Define it in case of PWM based control mode.
+ - pwms and pwm-names: Please refer to Documentation/devicetree/bindings/pwm/pwm.txt.
+
+
+Example 1:
+Brightness is I2C only mode. Backlight device name is 'lcd'.
+
+&i2c4 {
+ clock-frequency = <400000>;
+
+ lm3631@29 {
+ compatible = "ti,lm3631";
+ reg = <0x29>;
+
+ /* GPIO134 for HWEN pin */
+ ti,en-gpio = <&gpio5 6 0>;
+
+ backlight {
+ compatible = "ti,lm3631-backlight";
+ bl-name = "lcd";
+ full-strings-used;
+ };
+};
+
+Example 2:
+LM3631 brightness is controlled by PWM3943 controller.
+PWM3943 is a PWM controller. PWM#1 is port number of PMW3943.
+
+&i2c4 {
+ clock-frequency = <400000>;
+
+ lm3631@29 {
+ compatible = "ti,lm3631";
+ reg = <0x29>;
+
+ /* GPIO134 for HWEN pin */
+ ti,en-gpio = <&gpio5 6 0>;
+
+ backlight {
+ compatible = "ti,lm3631-backlight";
+ bl-name = "lcd";
+ full-strings-used;
+ mode-pwm-only;
+
+ pwm-period = <10000>;
+
+ pwms = <&pwm3943 1 10000>;
+ pwm-names = "lm3631-backlight";
+ };
+};
diff --git a/Examples/board-plat-lm3631.c b/Examples/board-plat-lm3631.c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Platform Specific LM3631 Example
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/mfd/lm3631.h>
+#include <linux/pwm.h>
+
+#include "mux.h"
+#include "board-plat-lm3631.h"
+
+static struct regulator_consumer_supply lcd_vboost[] = {
+ REGULATOR_SUPPLY("lcd_boost", NULL),
+};
+
+static struct regulator_consumer_supply lcd_vio[] = {
+ REGULATOR_SUPPLY("lcd_io", NULL),
+};
+
+static struct regulator_consumer_supply lcd_vpos[] = {
+ REGULATOR_SUPPLY("lcd_vpos", NULL),
+};
+
+static struct regulator_consumer_supply lcd_vneg[] = {
+ REGULATOR_SUPPLY("lcd_vneg", NULL),
+};
+
+static struct regulator_consumer_supply lcd_vgamma[] = {
+ REGULATOR_SUPPLY("lcd_gamma", NULL),
+};
+
+struct regulator_init_data lcd_boost = {
+ .constraints = {
+ .name = "LCD_BOOST",
+ .min_uV = 4500000,
+ .max_uV = 6350000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(lcd_vboost),
+ .consumer_supplies = lcd_vboost,
+};
+
+struct regulator_init_data lcd_cont = {
+ .constraints = {
+ .name = "LCD_CONT",
+ .min_uV = 1800000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(lcd_vio),
+ .consumer_supplies = lcd_vio,
+};
+
+struct regulator_init_data lcd_oref = {
+ .constraints = {
+ .name = "LCD_OREF",
+ .min_uV = 4000000,
+ .max_uV = 6000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(lcd_vgamma),
+ .consumer_supplies = lcd_vgamma,
+};
+
+struct regulator_init_data lcd_pos = {
+ .constraints = {
+ .name = "LCD_VPOS",
+ .min_uV = 4000000,
+ .max_uV = 6000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(lcd_vpos),
+ .consumer_supplies = lcd_vpos,
+};
+
+struct regulator_init_data lcd_neg = {
+ .constraints = {
+ .name = "LCD_VNEG",
+ .min_uV = 4000000,
+ .max_uV = 6000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(lcd_vneg),
+ .consumer_supplies = lcd_vneg,
+};
+
+struct lm3631_backlight_platform_data lm3631_bl_pdata = {
+ .name = "lcd-bl",
+ .is_full_strings = true,
+ .mode = LM3631_COMB1,
+};
+
+#define LM3631_EN_GPIO 134
+static struct lm3631_platform_data lm3631_pdata = {
+ .en_gpio = LM3631_EN_GPIO,
+ .regulator_data = {
+ &lcd_boost,
+ &lcd_cont,
+ &lcd_oref,
+ &lcd_pos,
+ &lcd_neg,
+ },
+ .bl_pdata = &lm3631_bl_pdata,
+};
+
+static struct i2c_board_info __initdata led_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("lm3631", 0x29),
+ .platform_data = &lm3631_pdata,
+ },
+};
+
+int plat_lm3631_init(void)
+{
+ i2c_register_board_info(4, led_i2c_boardinfo,
+ ARRAY_SIZE(led_i2c_boardinfo));
+ return 0;
+}
diff --git a/Examples/lm-lcd-driver.c b/Examples/lm-lcd-driver.c
--- /dev/null
+++ b/Examples/lm-lcd-driver.c
@@ -0,0 +1,112 @@
+/*
+ * LCD Driver Example
+ *
+ * Copyright 2013 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define LCD_BOOST_VOUT 5800000
+#define LCD_BIAS_VOUT 5500000
+
+enum lcd_ldo_id {
+ VBOOST,
+ VPOS,
+ VNEG,
+ NUM_REGULATORS,
+};
+
+const char *supplies[] = { "lcd_boost", "lcd_vpos", "lcd_vneg", };
+
+struct lcd_ctrl {
+ struct regulator *r[NUM_REGULATORS];
+ struct device *dev;
+};
+
+static int lm_lcd_enable(struct lcd_ctrl *ctl, enum lcd_ldo_id id, int enable)
+{
+ if (!ctl->r[id]) {
+ dev_info(ctl->dev, "regulator is not ready\n");
+ return 0;
+ }
+
+ if (enable)
+ return regulator_enable(ctl->r[id]);
+ else
+ return regulator_disable(ctl->r[id]);
+}
+
+static int lm_lcd_set_voltage(struct lcd_ctrl *ctl, enum lcd_ldo_id id, int uV)
+{
+ return regulator_set_voltage(ctl->r[id], uV, uV + 10000);
+}
+
+static int lm_lcd_probe(struct platform_device *pdev)
+{
+ struct lcd_ctrl *ctl;
+ struct device *dev = &pdev->dev;
+ struct regulator *r;
+ int i;
+
+ ctl = devm_kzalloc(dev, sizeof(*ctl), GFP_KERNEL);
+ if (!ctl)
+ return -ENOMEM;
+
+ ctl->dev = dev;
+
+ for (i = 0; i < NUM_REGULATORS; i++) {
+ r = devm_regulator_get(dev, supplies[i]);
+ if (IS_ERR(r))
+ continue;
+
+ ctl->r[i] = r;
+ }
+
+ platform_set_drvdata(pdev, ctl);
+
+ lm_lcd_set_voltage(ctl, VBOOST, LCD_BOOST_VOUT);
+ lm_lcd_set_voltage(ctl, VPOS, LCD_BIAS_VOUT);
+ lm_lcd_set_voltage(ctl, VNEG, LCD_BIAS_VOUT);
+
+ lm_lcd_enable(ctl, VPOS, 1);
+ lm_lcd_enable(ctl, VNEG, 1);
+
+ return 0;
+}
+
+static int lm_lcd_remove(struct platform_device *pdev)
+{
+ struct lcd_ctrl *ctl = platform_get_drvdata(pdev);
+
+ lm_lcd_enable(ctl, VPOS, 0);
+ lm_lcd_enable(ctl, VNEG, 0);
+
+ return 0;
+}
+
+static struct platform_driver lcd_ctrl_driver = {
+ .probe = lm_lcd_probe,
+ .remove = lm_lcd_remove,
+ .driver = {
+ .name = "lm-lcd-driver",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(lcd_ctrl_driver);
+
+MODULE_DESCRIPTION("LCD Controller Driver Example");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm-lcd-driver");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 49bb445d846aa76e206dfe7fb7d30ad5f24b6b97..28e29fcb7e49b031ba0fa8c85135d71b27674e06 100644 (file)
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
individual components like LCD backlight, LEDs, GPIOs and Kepad
under the corresponding menus.
+config MFD_LM3631
+ tristate "TI LM3631 Backlight and Bias Power Driver"
+ depends on I2C
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Say yes here to enable support for TI LM3631 chip.
+ LM3631 has 2 strings for backlight with 5 regulators for LCD bias.
+
config MFD_AAT2870_CORE
bool "AnalogicTech AAT2870"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5aea5ef0a62f51eff03a14404569c68a7700262f..109247099be48de1dde321f27d25fbd1605e9bad 100644 (file)
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
obj-$(CONFIG_MFD_LP3943) += lp3943.o
+obj-$(CONFIG_MFD_LM3631) += lm3631.o
obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
da9055-objs := da9055-core.o da9055-i2c.o
diff --git a/drivers/mfd/lm3631.c b/drivers/mfd/lm3631.c
--- /dev/null
+++ b/drivers/mfd/lm3631.c
@@ -0,0 +1,204 @@
+/*
+ * TI LM3631 MFD Driver
+ *
+ * Copyright 2013 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/lm3631.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+
+#define LM3631_DEV_LCD_BIAS(_id) \
+{ \
+ .name = "lm3631-regulator", \
+ .id = _id, \
+ .of_compatible = "ti,lm3631-regulator", \
+}
+
+#define LM3631_DEV_BL \
+{ \
+ .name = "lm3631-backlight", \
+ .of_compatible = "ti,lm3631-backlight", \
+}
+
+static struct mfd_cell lm3631_devs[] = {
+ /* 5 Regulators */
+ LM3631_DEV_LCD_BIAS(1),
+ LM3631_DEV_LCD_BIAS(2),
+ LM3631_DEV_LCD_BIAS(3),
+ LM3631_DEV_LCD_BIAS(4),
+ LM3631_DEV_LCD_BIAS(5),
+
+ /* Backlight */
+ LM3631_DEV_BL,
+};
+
+int lm3631_read_byte(struct lm3631 *lm3631, u8 reg, u8 *read)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(lm3631->regmap, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ *read = (u8)val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lm3631_read_byte);
+
+int lm3631_write_byte(struct lm3631 *lm3631, u8 reg, u8 data)
+{
+ return regmap_write(lm3631->regmap, reg, data);
+}
+EXPORT_SYMBOL_GPL(lm3631_write_byte);
+
+int lm3631_update_bits(struct lm3631 *lm3631, u8 reg, u8 mask, u8 data)
+{
+ return regmap_update_bits(lm3631->regmap, reg, mask, data);
+}
+EXPORT_SYMBOL_GPL(lm3631_update_bits);
+
+static int lm3631_init_device(struct lm3631 *lm3631)
+{
+ int ret;
+
+ /*
+ * Sequence
+ *
+ * 1) Enable nRST pin
+ * 2) Delay about 1ms (bias delay 200us + EPROM read time 700us)
+ * 3) Set LCD_EN bit to 1
+ */
+
+ ret = devm_gpio_request_one(lm3631->dev, lm3631->pdata->en_gpio,
+ GPIOF_OUT_INIT_HIGH, "lm3631_hwen");
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 1500);
+
+ return lm3631_update_bits(lm3631, LM3631_REG_DEVCTRL,
+ LM3631_LCD_EN_MASK,
+ 1 << LM3631_LCD_EN_SHIFT);
+}
+
+static void lm3631_deinit_device(struct lm3631 *lm3631)
+{
+ gpio_set_value(lm3631->pdata->en_gpio, 0);
+}
+
+static int lm3631_parse_dt(struct device *dev, struct lm3631 *lm3631)
+{
+ struct device_node *node = dev->of_node;
+ struct lm3631_platform_data *pdata;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->en_gpio = of_get_named_gpio(node, "ti,en-gpio", 0);
+ if (pdata->en_gpio == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ lm3631->pdata = pdata;
+
+ return 0;
+}
+
+static struct regmap_config lm3631_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LM3631_MAX_REGISTERS,
+};
+
+static int lm3631_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+ struct lm3631 *lm3631;
+ struct device *dev = &cl->dev;
+ struct lm3631_platform_data *pdata = dev_get_platdata(dev);
+ int ret;
+
+ lm3631 = devm_kzalloc(dev, sizeof(*lm3631), GFP_KERNEL);
+ if (!lm3631)
+ return -ENOMEM;
+
+ lm3631->pdata = pdata;
+ if (!pdata) {
+ if (IS_ENABLED(CONFIG_OF))
+ ret = lm3631_parse_dt(dev, lm3631);
+ else
+ ret = -ENODEV;
+
+ if (ret)
+ return ret;
+ }
+
+ lm3631->regmap = devm_regmap_init_i2c(cl, &lm3631_regmap_config);
+ if (IS_ERR(lm3631->regmap))
+ return PTR_ERR(lm3631->regmap);
+
+ lm3631->dev = &cl->dev;
+ i2c_set_clientdata(cl, lm3631);
+
+ ret = lm3631_init_device(lm3631);
+ if (ret)
+ return ret;
+
+ return mfd_add_devices(dev, -1, lm3631_devs, ARRAY_SIZE(lm3631_devs),
+ NULL, 0, NULL);
+}
+
+static int lm3631_remove(struct i2c_client *cl)
+{
+ struct lm3631 *lm3631 = i2c_get_clientdata(cl);
+
+ lm3631_deinit_device(lm3631);
+ mfd_remove_devices(lm3631->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm3631_ids[] = {
+ { "lm3631", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm3631_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm3631_of_match[] = {
+ { .compatible = "ti,lm3631", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3631_of_match);
+#endif
+
+static struct i2c_driver lm3631_driver = {
+ .probe = lm3631_probe,
+ .remove = lm3631_remove,
+ .driver = {
+ .name = "lm3631",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lm3631_of_match),
+ },
+ .id_table = lm3631_ids,
+};
+module_i2c_driver(lm3631_driver);
+
+MODULE_DESCRIPTION("TI LM3631 MFD Core");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
index 6a7932822e373317caba9c5c799c9439f5444927..df9c16fc0171b37b91716eb1269c957b078b026d 100644 (file)
This driver provides support for the voltage regulators of the
PCAP2 PMIC.
+config REGULATOR_LM3631
+ tristate "TI LM3631 voltage regulators"
+ depends on MFD_LM3631
+ help
+ This driver supports LM3631 voltage regulators for the LCD bias.
+
config REGULATOR_PCF50633
tristate "NXP PCF50633 regulator driver"
depends on MFD_PCF50633
index 979f9ddcf259bd5a82b6b5d91f81981902e6185c..b20070d9799267a228569d23b23247c4ff78322a 100644 (file)
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
+obj-$(CONFIG_REGULATOR_LM3631) += lm3631-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
diff --git a/drivers/regulator/lm3631-regulator.c b/drivers/regulator/lm3631-regulator.c
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * TI LM3631 LDO Regulator Driver
+ *
+ * Copyright 2013 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/mfd/lm3631.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+#define ENABLE_TIME_USEC 1000
+
+enum lm3631_regulator_id {
+ LM3631_REGULATOR_BOOST,
+ LM3631_LDO_CONT,
+ LM3631_LDO_OREF,
+ LM3631_LDO_POS,
+ LM3631_LDO_NEG,
+};
+
+struct lm3631_regulator {
+ struct lm3631 *lm3631;
+ struct regulator_desc *desc;
+ struct regulator_dev *regulator;
+ struct regulator_init_data *init_data;
+};
+
+static const int lm3631_boost_vtbl[] = {
+ 4500000, 4550000, 4600000, 4650000, 4700000, 4750000, 4800000, 4850000,
+ 4900000, 4950000, 5000000, 5050000, 5100000, 5150000, 5200000, 5250000,
+ 5300000, 5350000, 5400000, 5450000, 5500000, 5550000, 5600000, 5650000,
+ 5700000, 5750000, 5800000, 5850000, 5900000, 5950000, 6000000, 6050000,
+ 6100000, 6150000, 6200000, 6250000, 6300000, 6350000,
+};
+
+static const int lm3631_ldo_cont_vtbl[] = {
+ 1800000, 2300000, 2800000, 3300000,
+};
+
+static const int lm3631_ldo_target_vtbl[] = {
+ 4000000, 4050000, 4100000, 4150000, 4200000, 4250000, 4300000, 4350000,
+ 4400000, 4450000, 4500000, 4550000, 4600000, 4650000, 4700000, 4750000,
+ 4800000, 4850000, 4900000, 4950000, 5000000, 5050000, 5100000, 5150000,
+ 5200000, 5250000, 5300000, 5350000, 5400000, 5450000, 5500000, 5550000,
+ 5600000, 5650000, 5700000, 5750000, 5800000, 5850000, 5900000, 5950000,
+ 6000000,
+};
+
+const int ldo_cont_enable_time[] = {
+ 0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
+};
+
+static int lm3631_regulator_enable_time(struct regulator_dev *rdev)
+{
+ struct lm3631_regulator *lm3631_regulator = rdev_get_drvdata(rdev);
+ enum lm3631_regulator_id id = rdev_get_id(rdev);
+ u8 val, addr, mask;
+
+ switch (id) {
+ case LM3631_LDO_CONT:
+ addr = LM3631_REG_ENTIME_VCONT;
+ mask = LM3631_ENTIME_CONT_MASK;
+ break;
+ case LM3631_LDO_OREF:
+ addr = LM3631_REG_ENTIME_VOREF;
+ mask = LM3631_ENTIME_MASK;
+ break;
+ case LM3631_LDO_POS:
+ addr = LM3631_REG_ENTIME_VPOS;
+ mask = LM3631_ENTIME_MASK;
+ break;
+ case LM3631_LDO_NEG:
+ addr = LM3631_REG_ENTIME_VNEG;
+ mask = LM3631_ENTIME_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (lm3631_read_byte(lm3631_regulator->lm3631, addr, &val))
+ return -EINVAL;
+
+ val = (val & mask) >> LM3631_ENTIME_SHIFT;
+
+ if (id == LM3631_LDO_CONT)
+ return ldo_cont_enable_time[val];
+ else
+ return ENABLE_TIME_USEC * val;
+}
+
+static struct regulator_ops lm3631_boost_voltage_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops lm3631_regulator_voltage_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lm3631_regulator_enable_time,
+};
+
+static struct regulator_desc lm3631_regulator_desc[] = {
+ {
+ .name = "vboost",
+ .id = LM3631_REGULATOR_BOOST,
+ .ops = &lm3631_boost_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lm3631_boost_vtbl),
+ .volt_table = lm3631_boost_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_BOOST,
+ .vsel_mask = LM3631_VOUT_MASK,
+ },
+ {
+ .name = "ldo_cont",
+ .id = LM3631_LDO_CONT,
+ .ops = &lm3631_regulator_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lm3631_ldo_cont_vtbl),
+ .volt_table = lm3631_ldo_cont_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_CONT,
+ .vsel_mask = LM3631_VOUT_CONT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL2,
+ .enable_mask = LM3631_EN_CONT_MASK,
+ },
+ {
+ .name = "ldo_oref",
+ .id = LM3631_LDO_OREF,
+ .ops = &lm3631_regulator_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lm3631_ldo_target_vtbl),
+ .volt_table = lm3631_ldo_target_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_OREF,
+ .vsel_mask = LM3631_VOUT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL1,
+ .enable_mask = LM3631_EN_OREF_MASK,
+ },
+ {
+ .name = "ldo_vpos",
+ .id = LM3631_LDO_POS,
+ .ops = &lm3631_regulator_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lm3631_ldo_target_vtbl),
+ .volt_table = lm3631_ldo_target_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_POS,
+ .vsel_mask = LM3631_VOUT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL1,
+ .enable_mask = LM3631_EN_VPOS_MASK,
+ },
+ {
+ .name = "ldo_vneg",
+ .id = LM3631_LDO_NEG,
+ .ops = &lm3631_regulator_voltage_table_ops,
+ .n_voltages = ARRAY_SIZE(lm3631_ldo_target_vtbl),
+ .volt_table = lm3631_ldo_target_vtbl,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .vsel_reg = LM3631_REG_VOUT_NEG,
+ .vsel_mask = LM3631_VOUT_MASK,
+ .enable_reg = LM3631_REG_LDO_CTRL1,
+ .enable_mask = LM3631_EN_VNEG_MASK,
+ },
+};
+
+static struct of_regulator_match lm3631_regulator_matches[] = {
+ { .name = "vboost", .driver_data = (void *)LM3631_REGULATOR_BOOST, },
+ { .name = "vcont", .driver_data = (void *)LM3631_LDO_CONT, },
+ { .name = "voref", .driver_data = (void *)LM3631_LDO_OREF, },
+ { .name = "vpos", .driver_data = (void *)LM3631_LDO_POS, },
+ { .name = "vneg", .driver_data = (void *)LM3631_LDO_NEG, },
+};
+
+static int lm3631_regulator_parse_dt(struct device *dev,
+ struct lm3631_regulator *lm3631_regulator,
+ int id)
+{
+ struct device_node *node = dev->of_node;
+ int count;
+
+ count = of_regulator_match(dev, node, &lm3631_regulator_matches[id], 1);
+ if (count <= 0)
+ return -ENODEV;
+
+ lm3631_regulator->init_data = lm3631_regulator_matches[id].init_data;
+
+ return 0;
+}
+
+static int lm3631_regulator_probe(struct platform_device *pdev)
+{
+ struct lm3631 *lm3631 = dev_get_drvdata(pdev->dev.parent);
+ struct lm3631_regulator *lm3631_regulator;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ int id = pdev->id;
+ int ret;
+
+ lm3631_regulator = devm_kzalloc(&pdev->dev, sizeof(*lm3631_regulator),
+ GFP_KERNEL);
+ if (!lm3631_regulator)
+ return -ENOMEM;
+
+ lm3631_regulator->lm3631 = lm3631;
+
+ lm3631_regulator->init_data = lm3631->pdata->regulator_data[id];
+ if (!lm3631_regulator->init_data) {
+ if (IS_ENABLED(CONFIG_OF))
+ ret = lm3631_regulator_parse_dt(&pdev->dev,
+ lm3631_regulator, id);
+ else
+ ret = -ENODEV;
+
+ if (ret)
+ return ret;
+ }
+
+ cfg.dev = pdev->dev.parent;
+ cfg.init_data = lm3631_regulator->init_data;
+ cfg.driver_data = lm3631_regulator;
+ cfg.regmap = lm3631->regmap;
+
+ rdev = regulator_register(&lm3631_regulator_desc[id], &cfg);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(&pdev->dev, "[%d] regulator register err: %d\n",
+ id + 1, ret);
+ return ret;
+ }
+
+ lm3631_regulator->regulator = rdev;
+ platform_set_drvdata(pdev, lm3631_regulator);
+
+ return 0;
+}
+
+static int lm3631_regulator_remove(struct platform_device *pdev)
+{
+ struct lm3631_regulator *lm3631_regulator = platform_get_drvdata(pdev);
+
+ regulator_unregister(lm3631_regulator->regulator);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm3631_regulator_of_match[] = {
+ { .compatible = "ti,lm3631-regulator", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3631_regulator_of_match);
+#endif
+
+static struct platform_driver lm3631_regulator_driver = {
+ .probe = lm3631_regulator_probe,
+ .remove = lm3631_regulator_remove,
+ .driver = {
+ .name = "lm3631-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lm3631_regulator_of_match),
+ },
+};
+
+module_platform_driver(lm3631_regulator_driver);
+
+MODULE_DESCRIPTION("TI LM3631 Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm3631-regulator");
index 4341377fb2614f6cac62d909c16a56cc25d5aab1..bdba28adeab8b7595d8d9ca6e323f64d54d68793 100644 (file)
help
This supports TI LM3630A Backlight Driver
+config BACKLIGHT_LM3631
+ tristate "Backlight driver for TI LM3631"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_LM3631
+ help
+ Say Y to enable the backlight driver for TI LM3631.
+
config BACKLIGHT_LM3639
tristate "Backlight Driver for LM3639"
depends on BACKLIGHT_CLASS_DEVICE && I2C
index ffd0717bf30dd99ac3266afec30488be444c2c74..d3d48e8eb3158a12e5568d191db13416be1cc5c2 100644 (file)
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3585) += lm3585_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3631) += lm3631_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
obj-$(CONFIG_BACKLIGHT_LM36923) += lm36923_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
diff --git a/drivers/video/backlight/lm3631_bl.c b/drivers/video/backlight/lm3631_bl.c
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * TI LM3631 Backlight Driver
+ *
+ * Copyright 2013 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mfd/lm3631.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define LM3631_MAX_BRIGHTNESS 2047
+
+#define DEFAULT_BL_NAME "lcd-backlight"
+
+enum lm3631_bl_ctrl_mode {
+ LMU_BL_I2C,
+ LMU_BL_PWM,
+};
+
+struct lm3631_bl {
+ struct device *dev;
+ struct backlight_device *bl_dev;
+
+ struct lm3631 *lm3631;
+ struct lm3631_backlight_platform_data *pdata;
+ enum lm3631_bl_ctrl_mode mode;
+
+ struct pwm_device *pwm;
+};
+
+static int lm3631_bl_enable(struct lm3631_bl *lm3631_bl, int enable)
+{
+ return lm3631_update_bits(lm3631_bl->lm3631, LM3631_REG_DEVCTRL,
+ LM3631_BL_EN_MASK,
+ enable << LM3631_BL_EN_SHIFT);
+}
+
+static void lm3631_bl_pwm_ctrl(struct lm3631_bl *lm3631_bl, int br, int max_br)
+{
+ unsigned int period;
+ unsigned int duty;
+ struct pwm_device *pwm;
+
+ if (!lm3631_bl->pdata)
+ return;
+
+ period = lm3631_bl->pdata->pwm_period;
+ duty = br * period / max_br;
+
+ /* Request a PWM device with the consumer name */
+ if (!lm3631_bl->pwm) {
+ pwm = devm_pwm_get(lm3631_bl->dev, "lm3631-backlight");
+ if (IS_ERR(pwm)) {
+ dev_err(lm3631_bl->dev, "can not get PWM device\n");
+ return;
+ }
+ lm3631_bl->pwm = pwm;
+ }
+
+ pwm_config(lm3631_bl->pwm, duty, period);
+ if (duty)
+ pwm_enable(lm3631_bl->pwm);
+ else
+ pwm_disable(lm3631_bl->pwm);
+}
+
+static inline int lm3631_bl_set_brightness(struct lm3631_bl *lm3631_bl, int val)
+{
+ u8 data;
+ int ret;
+
+ data = val & LM3631_BRT_LSB_MASK;
+ ret = lm3631_update_bits(lm3631_bl->lm3631, LM3631_REG_BRT_LSB,
+ LM3631_BRT_LSB_MASK, data);
+ if (ret)
+ return ret;
+
+ data = (val >> LM3631_BRT_MSB_SHIFT) & 0xFF;
+ return lm3631_write_byte(lm3631_bl->lm3631, LM3631_REG_BRT_MSB,
+ data);
+}
+
+static int lm3631_bl_update_status(struct backlight_device *bl_dev)
+{
+ struct lm3631_bl *lm3631_bl = bl_get_data(bl_dev);
+ int brt;
+ int ret;
+
+ if (bl_dev->props.state & BL_CORE_SUSPENDED)
+ bl_dev->props.brightness = 0;
+
+ brt = bl_dev->props.brightness;
+
+ if (brt > 0)
+ ret = lm3631_bl_enable(lm3631_bl, 1);
+ else
+ ret = lm3631_bl_enable(lm3631_bl, 0);
+
+ if (ret)
+ return ret;
+
+ if (lm3631_bl->mode == LMU_BL_PWM)
+ lm3631_bl_pwm_ctrl(lm3631_bl, brt,
+ bl_dev->props.max_brightness);
+ else
+ ret = lm3631_bl_set_brightness(lm3631_bl, brt);
+
+ return ret;
+}
+
+static int lm3631_bl_get_brightness(struct backlight_device *bl_dev)
+{
+ return bl_dev->props.brightness;
+}
+
+static const struct backlight_ops lm3631_bl_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = lm3631_bl_update_status,
+ .get_brightness = lm3631_bl_get_brightness,
+};
+
+static int lm3631_bl_register(struct lm3631_bl *lm3631_bl)
+{
+ struct backlight_device *bl_dev;
+ struct backlight_properties props;
+ struct lm3631_backlight_platform_data *pdata = lm3631_bl->pdata;
+ char name[20];
+
+ props.type = BACKLIGHT_PLATFORM;
+ props.brightness = pdata ? pdata->init_brightness : 0;
+ props.max_brightness = LM3631_MAX_BRIGHTNESS;
+
+ if (!pdata || !pdata->name)
+ snprintf(name, sizeof(name), "%s", DEFAULT_BL_NAME);
+ else
+ snprintf(name, sizeof(name), "%s", pdata->name);
+
+ bl_dev = backlight_device_register(name, lm3631_bl->dev, lm3631_bl,
+ &lm3631_bl_ops, &props);
+ if (IS_ERR(bl_dev))
+ return PTR_ERR(bl_dev);
+
+ lm3631_bl->bl_dev = bl_dev;
+
+ return 0;
+}
+
+static void lm3631_bl_unregister(struct lm3631_bl *lm3631_bl)
+{
+ if (lm3631_bl->bl_dev)
+ backlight_device_unregister(lm3631_bl->bl_dev);
+}
+
+static int lm3631_bl_set_ctrl_mode(struct lm3631_bl *lm3631_bl)
+{
+ struct lm3631_backlight_platform_data *pdata = lm3631_bl->pdata;
+
+ /* Brightness control mode is I2C only by default */
+ if (!pdata) {
+ lm3631_bl->mode = LMU_BL_I2C;
+ return lm3631_update_bits(lm3631_bl->lm3631,
+ LM3631_REG_BRT_MODE, LM3631_BRT_MASK,
+ LM3631_I2C_ONLY);
+ }
+
+ if (pdata->pwm_period > 0)
+ lm3631_bl->mode = LMU_BL_PWM;
+
+ return lm3631_update_bits(lm3631_bl->lm3631, LM3631_REG_BRT_MODE,
+ LM3631_BRT_MASK, pdata->mode);
+}
+
+static int lm3631_bl_string_configure(struct lm3631_bl *lm3631_bl)
+{
+ u8 val;
+
+ if (lm3631_bl->pdata->is_full_strings)
+ val = LM3631_BL_TWO_STRINGS;
+ else
+ val = LM3631_BL_ONE_STRING;
+
+ return lm3631_update_bits(lm3631_bl->lm3631, LM3631_REG_BL_CFG,
+ LM3631_BL_STRING_MASK, val);
+}
+
+static int lm3631_bl_configure(struct lm3631_bl *lm3631_bl)
+{
+ int ret;
+
+ ret = lm3631_bl_set_ctrl_mode(lm3631_bl);
+ if (ret)
+ return ret;
+
+ return lm3631_bl_string_configure(lm3631_bl);
+}
+
+static int lm3631_bl_parse_dt(struct device *dev, struct lm3631_bl *lm3631_bl)
+{
+ struct device_node *node = dev->of_node;
+ struct lm3631_backlight_platform_data *pdata;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ of_property_read_string(node, "bl-name", &pdata->name);
+
+ if (of_find_property(node, "full-strings-used", NULL))
+ pdata->is_full_strings = true;
+
+ if (of_find_property(node, "mode-pwm-only", NULL))
+ pdata->mode = LM3631_PWM_ONLY;
+ else if (of_find_property(node, "mode-comb1", NULL))
+ pdata->mode = LM3631_COMB1;
+ else if (of_find_property(node, "mode-comb2", NULL))
+ pdata->mode = LM3631_COMB2;
+
+ of_property_read_u8(node, "initial-brightness",
+ (u8 *)&pdata->init_brightness);
+
+ of_property_read_u32(node, "pwm-period", &pdata->pwm_period);
+
+ lm3631_bl->pdata = pdata;
+
+ return 0;
+}
+
+static int lm3631_bl_probe(struct platform_device *pdev)
+{
+ struct lm3631 *lm3631 = dev_get_drvdata(pdev->dev.parent);
+ struct lm3631_backlight_platform_data *pdata = lm3631->pdata->bl_pdata;
+ struct lm3631_bl *lm3631_bl;
+ int ret;
+
+ lm3631_bl = devm_kzalloc(&pdev->dev, sizeof(*lm3631_bl), GFP_KERNEL);
+ if (!lm3631_bl)
+ return -ENOMEM;
+
+ lm3631_bl->pdata = pdata;
+ if (!lm3631_bl->pdata) {
+ if (IS_ENABLED(CONFIG_OF))
+ ret = lm3631_bl_parse_dt(&pdev->dev, lm3631_bl);
+ else
+ return -ENODEV;
+
+ if (ret)
+ return ret;
+ }
+
+ lm3631_bl->dev = &pdev->dev;
+ lm3631_bl->lm3631 = lm3631;
+ platform_set_drvdata(pdev, lm3631_bl);
+
+ ret = lm3631_bl_configure(lm3631_bl);
+ if (ret) {
+ dev_err(&pdev->dev, "backlight config err: %d\n", ret);
+ return ret;
+ }
+
+ ret = lm3631_bl_register(lm3631_bl);
+ if (ret) {
+ dev_err(&pdev->dev, "register backlight err: %d\n", ret);
+ return ret;
+ }
+
+ backlight_update_status(lm3631_bl->bl_dev);
+
+ return 0;
+}
+
+static int lm3631_bl_remove(struct platform_device *pdev)
+{
+ struct lm3631_bl *lm3631_bl = platform_get_drvdata(pdev);
+ struct backlight_device *bl_dev = lm3631_bl->bl_dev;
+
+ bl_dev->props.brightness = 0;
+ backlight_update_status(bl_dev);
+ lm3631_bl_unregister(lm3631_bl);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm3631_bl_of_match[] = {
+ { .compatible = "ti,lm3631-backlight", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3631_bl_of_match);
+#endif
+
+static struct platform_driver lm3631_bl_driver = {
+ .probe = lm3631_bl_probe,
+ .remove = lm3631_bl_remove,
+ .driver = {
+ .name = "lm3631-backlight",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lm3631_bl_of_match),
+ },
+};
+module_platform_driver(lm3631_bl_driver);
+
+MODULE_DESCRIPTION("TI LM3631 Backlight Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm3631-backlight");
diff --git a/include/linux/mfd/lm3631.h b/include/linux/mfd/lm3631.h
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * TI LM3631 MFD Driver
+ *
+ * Copyright 2013 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __MFD_LM3631_H__
+#define __MFD_LM3631_H__
+
+#include <linux/gpio.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/machine.h>
+
+/* Registers */
+#define LM3631_REG_DEVCTRL 0x00
+#define LM3631_LCD_EN_MASK BIT(1)
+#define LM3631_LCD_EN_SHIFT 1
+#define LM3631_BL_EN_MASK BIT(0)
+#define LM3631_BL_EN_SHIFT 0
+
+#define LM3631_REG_BRT_LSB 0x01
+#define LM3631_BRT_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
+#define LM3631_REG_BRT_MSB 0x02
+#define LM3631_BRT_MSB_SHIFT 3
+
+#define LM3631_REG_BL_CFG 0x06
+#define LM3631_BL_STRING_MASK BIT(3)
+#define LM3631_BL_TWO_STRINGS 0
+#define LM3631_BL_ONE_STRING BIT(3)
+
+#define LM3631_REG_BRT_MODE 0x08
+#define LM3631_BRT_MASK (BIT(2) | BIT(3))
+
+#define LM3631_REG_LDO_CTRL1 0x0A
+#define LM3631_EN_OREF_MASK BIT(0)
+#define LM3631_EN_VNEG_MASK BIT(1)
+#define LM3631_EN_VPOS_MASK BIT(2)
+
+#define LM3631_REG_LDO_CTRL2 0x0B
+#define LM3631_EN_CONT_MASK BIT(0)
+
+#define LM3631_REG_VOUT_CONT 0x0C
+#define LM3631_VOUT_CONT_MASK (BIT(6) | BIT(7))
+
+#define LM3631_REG_VOUT_BOOST 0x0C
+#define LM3631_REG_VOUT_POS 0x0D
+#define LM3631_REG_VOUT_NEG 0x0E
+#define LM3631_REG_VOUT_OREF 0x0F
+#define LM3631_VOUT_MASK 0x3F
+
+#define LM3631_REG_ENTIME_VCONT 0x0B
+#define LM3631_ENTIME_CONT_MASK 0x70
+
+#define LM3631_REG_ENTIME_VOREF 0x0F
+#define LM3631_REG_ENTIME_VPOS 0x10
+#define LM3631_REG_ENTIME_VNEG 0x11
+#define LM3631_ENTIME_MASK 0xF0
+#define LM3631_ENTIME_SHIFT 4
+
+#define LM3631_MAX_REGISTERS 0x16
+
+#define LM3631_NUM_REGULATORS 5
+
+enum lm3631_brightness_mode {
+ LM3631_I2C_ONLY = 0 << 2,
+ LM3631_PWM_ONLY = 1 << 2,
+ LM3631_COMB1 = 2 << 2, /* I2C x PWM befoer sloping */
+ LM3631_COMB2 = 3 << 2, /* Sloped I2C x PWM */
+};
+
+/*
+ * struct lm3633_bl_platform_data
+ * @name: Backlight driver name
+ * @is_full_strings: set true if two strings are used
+ * @init_brightness: Initial brightness value
+ * @mode: Backlight control mode
+ * @pwm_period: Platform specific PWM period value. unit is nano
+ */
+struct lm3631_backlight_platform_data {
+ const char *name;
+ bool is_full_strings;
+ u8 init_brightness;
+ enum lm3631_brightness_mode mode;
+
+ /* Only valid in case of PWM mode */
+ unsigned int pwm_period;
+};
+
+/*
+ * struct lmu_platform_data
+ * @en_gpio: GPIO for nRST pin
+ * @regulator_data: Regulator initial data for LCD bias
+ * @bl_pdata: Backlight platform data
+ */
+struct lm3631_platform_data {
+ int en_gpio;
+ struct regulator_init_data *regulator_data[LM3631_NUM_REGULATORS];
+ struct lm3631_backlight_platform_data *bl_pdata;
+};
+
+/*
+ * struct lm3631
+ * @dev: Parent device pointer
+ * @regmap: Used for i2c communcation on accessing registers
+ * @pdata: LMU platform specific data
+ */
+struct lm3631 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct lm3631_platform_data *pdata;
+};
+
+int lm3631_read_byte(struct lm3631 *lm3631, u8 reg, u8 *read);
+int lm3631_write_byte(struct lm3631 *lm3631, u8 reg, u8 data);
+int lm3631_update_bits(struct lm3631 *lm3631, u8 reg, u8 mask, u8 data);
+#endif