1 /*
2 * TI LM3631 MFD Driver
3 *
4 * Copyright 2013 Texas Instruments
5 *
6 * Author: Milo Kim <milo.kim@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
14 #include <linux/delay.h>
15 #include <linux/err.h>
16 #include <linux/gpio.h>
17 #include <linux/i2c.h>
18 #include <linux/mfd/core.h>
19 #include <linux/mfd/lm3631.h>
20 #include <linux/module.h>
21 #include <linux/of.h>
22 #include <linux/of_gpio.h>
23 #include <linux/slab.h>
25 #define LM3631_DEV_LCD_BIAS(_id) \
26 { \
27 .name = "lm3631-regulator", \
28 .id = _id, \
29 .of_compatible = "ti,lm3631-regulator", \
30 }
32 #define LM3631_DEV_BL \
33 { \
34 .name = "lm3631-backlight", \
35 .of_compatible = "ti,lm3631-backlight", \
36 }
38 static struct mfd_cell lm3631_devs[] = {
39 /* 5 Regulators */
40 LM3631_DEV_LCD_BIAS(1),
41 LM3631_DEV_LCD_BIAS(2),
42 LM3631_DEV_LCD_BIAS(3),
43 LM3631_DEV_LCD_BIAS(4),
44 LM3631_DEV_LCD_BIAS(5),
46 /* Backlight */
47 LM3631_DEV_BL,
48 };
50 int lm3631_read_byte(struct lm3631 *lm3631, u8 reg, u8 *read)
51 {
52 int ret;
53 unsigned int val;
55 ret = regmap_read(lm3631->regmap, reg, &val);
56 if (ret < 0)
57 return ret;
59 *read = (u8)val;
60 return 0;
61 }
62 EXPORT_SYMBOL_GPL(lm3631_read_byte);
64 int lm3631_write_byte(struct lm3631 *lm3631, u8 reg, u8 data)
65 {
66 return regmap_write(lm3631->regmap, reg, data);
67 }
68 EXPORT_SYMBOL_GPL(lm3631_write_byte);
70 int lm3631_update_bits(struct lm3631 *lm3631, u8 reg, u8 mask, u8 data)
71 {
72 return regmap_update_bits(lm3631->regmap, reg, mask, data);
73 }
74 EXPORT_SYMBOL_GPL(lm3631_update_bits);
76 static int lm3631_init_device(struct lm3631 *lm3631)
77 {
78 int ret;
80 /*
81 * Sequence
82 *
83 * 1) Enable nRST pin
84 * 2) Delay about 1ms (bias delay 200us + EPROM read time 700us)
85 * 3) Set LCD_EN bit to 1
86 */
88 ret = devm_gpio_request_one(lm3631->dev, lm3631->pdata->en_gpio,
89 GPIOF_OUT_INIT_HIGH, "lm3631_hwen");
90 if (ret)
91 return ret;
93 usleep_range(1000, 1500);
95 return lm3631_update_bits(lm3631, LM3631_REG_DEVCTRL,
96 LM3631_LCD_EN_MASK,
97 1 << LM3631_LCD_EN_SHIFT);
98 }
100 static void lm3631_deinit_device(struct lm3631 *lm3631)
101 {
102 gpio_set_value(lm3631->pdata->en_gpio, 0);
103 }
105 static int lm3631_parse_dt(struct device *dev, struct lm3631 *lm3631)
106 {
107 struct device_node *node = dev->of_node;
108 struct lm3631_platform_data *pdata;
110 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
111 if (!pdata)
112 return -ENOMEM;
114 pdata->en_gpio = of_get_named_gpio(node, "ti,en-gpio", 0);
115 if (pdata->en_gpio == -EPROBE_DEFER)
116 return -EPROBE_DEFER;
118 lm3631->pdata = pdata;
120 return 0;
121 }
123 static struct regmap_config lm3631_regmap_config = {
124 .reg_bits = 8,
125 .val_bits = 8,
126 .max_register = LM3631_MAX_REGISTERS,
127 };
129 static int lm3631_probe(struct i2c_client *cl, const struct i2c_device_id *id)
130 {
131 struct lm3631 *lm3631;
132 struct device *dev = &cl->dev;
133 struct lm3631_platform_data *pdata = dev_get_platdata(dev);
134 int ret;
136 lm3631 = devm_kzalloc(dev, sizeof(*lm3631), GFP_KERNEL);
137 if (!lm3631)
138 return -ENOMEM;
140 lm3631->pdata = pdata;
141 if (!pdata) {
142 if (IS_ENABLED(CONFIG_OF))
143 ret = lm3631_parse_dt(dev, lm3631);
144 else
145 ret = -ENODEV;
147 if (ret)
148 return ret;
149 }
151 lm3631->regmap = devm_regmap_init_i2c(cl, &lm3631_regmap_config);
152 if (IS_ERR(lm3631->regmap))
153 return PTR_ERR(lm3631->regmap);
155 lm3631->dev = &cl->dev;
156 i2c_set_clientdata(cl, lm3631);
158 ret = lm3631_init_device(lm3631);
159 if (ret)
160 return ret;
162 return mfd_add_devices(dev, -1, lm3631_devs, ARRAY_SIZE(lm3631_devs),
163 NULL, 0, NULL);
164 }
166 static int lm3631_remove(struct i2c_client *cl)
167 {
168 struct lm3631 *lm3631 = i2c_get_clientdata(cl);
170 lm3631_deinit_device(lm3631);
171 mfd_remove_devices(lm3631->dev);
173 return 0;
174 }
176 static const struct i2c_device_id lm3631_ids[] = {
177 { "lm3631", 0 },
178 { }
179 };
180 MODULE_DEVICE_TABLE(i2c, lm3631_ids);
182 #ifdef CONFIG_OF
183 static const struct of_device_id lm3631_of_match[] = {
184 { .compatible = "ti,lm3631", },
185 { }
186 };
187 MODULE_DEVICE_TABLE(of, lm3631_of_match);
188 #endif
190 static struct i2c_driver lm3631_driver = {
191 .probe = lm3631_probe,
192 .remove = lm3631_remove,
193 .driver = {
194 .name = "lm3631",
195 .owner = THIS_MODULE,
196 .of_match_table = of_match_ptr(lm3631_of_match),
197 },
198 .id_table = lm3631_ids,
199 };
200 module_i2c_driver(lm3631_driver);
202 MODULE_DESCRIPTION("TI LM3631 MFD Core");
203 MODULE_AUTHOR("Milo Kim");
204 MODULE_LICENSE("GPL");