xref: /openbmc/linux/drivers/mfd/tps65910.c (revision 75f25bd3)
1 /*
2  * tps65910.c  --  TI TPS6591x
3  *
4  * Copyright 2010 Texas Instruments Inc.
5  *
6  * Author: Graeme Gregory <gg@slimlogic.co.uk>
7  * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
8  *
9  *  This program is free software; you can redistribute it and/or modify it
10  *  under  the terms of the GNU General  Public License as published by the
11  *  Free Software Foundation;  either version 2 of the License, or (at your
12  *  option) any later version.
13  *
14  */
15 
16 #include <linux/module.h>
17 #include <linux/moduleparam.h>
18 #include <linux/init.h>
19 #include <linux/slab.h>
20 #include <linux/i2c.h>
21 #include <linux/gpio.h>
22 #include <linux/mfd/core.h>
23 #include <linux/mfd/tps65910.h>
24 
25 static struct mfd_cell tps65910s[] = {
26 	{
27 		.name = "tps65910-pmic",
28 	},
29 	{
30 		.name = "tps65910-rtc",
31 	},
32 	{
33 		.name = "tps65910-power",
34 	},
35 };
36 
37 
38 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
39 				  int bytes, void *dest)
40 {
41 	struct i2c_client *i2c = tps65910->i2c_client;
42 	struct i2c_msg xfer[2];
43 	int ret;
44 
45 	/* Write register */
46 	xfer[0].addr = i2c->addr;
47 	xfer[0].flags = 0;
48 	xfer[0].len = 1;
49 	xfer[0].buf = &reg;
50 
51 	/* Read data */
52 	xfer[1].addr = i2c->addr;
53 	xfer[1].flags = I2C_M_RD;
54 	xfer[1].len = bytes;
55 	xfer[1].buf = dest;
56 
57 	ret = i2c_transfer(i2c->adapter, xfer, 2);
58 	if (ret == 2)
59 		ret = 0;
60 	else if (ret >= 0)
61 		ret = -EIO;
62 
63 	return ret;
64 }
65 
66 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
67 				   int bytes, void *src)
68 {
69 	struct i2c_client *i2c = tps65910->i2c_client;
70 	/* we add 1 byte for device register */
71 	u8 msg[TPS65910_MAX_REGISTER + 1];
72 	int ret;
73 
74 	if (bytes > TPS65910_MAX_REGISTER)
75 		return -EINVAL;
76 
77 	msg[0] = reg;
78 	memcpy(&msg[1], src, bytes);
79 
80 	ret = i2c_master_send(i2c, msg, bytes + 1);
81 	if (ret < 0)
82 		return ret;
83 	if (ret != bytes + 1)
84 		return -EIO;
85 	return 0;
86 }
87 
88 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
89 {
90 	u8 data;
91 	int err;
92 
93 	mutex_lock(&tps65910->io_mutex);
94 	err = tps65910_i2c_read(tps65910, reg, 1, &data);
95 	if (err) {
96 		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
97 		goto out;
98 	}
99 
100 	data |= mask;
101 	err = tps65910_i2c_write(tps65910, reg, 1, &data);
102 	if (err)
103 		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
104 
105 out:
106 	mutex_unlock(&tps65910->io_mutex);
107 	return err;
108 }
109 EXPORT_SYMBOL_GPL(tps65910_set_bits);
110 
111 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
112 {
113 	u8 data;
114 	int err;
115 
116 	mutex_lock(&tps65910->io_mutex);
117 	err = tps65910_i2c_read(tps65910, reg, 1, &data);
118 	if (err) {
119 		dev_err(tps65910->dev, "read from reg %x failed\n", reg);
120 		goto out;
121 	}
122 
123 	data &= mask;
124 	err = tps65910_i2c_write(tps65910, reg, 1, &data);
125 	if (err)
126 		dev_err(tps65910->dev, "write to reg %x failed\n", reg);
127 
128 out:
129 	mutex_unlock(&tps65910->io_mutex);
130 	return err;
131 }
132 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
133 
134 static int tps65910_i2c_probe(struct i2c_client *i2c,
135 			    const struct i2c_device_id *id)
136 {
137 	struct tps65910 *tps65910;
138 	struct tps65910_board *pmic_plat_data;
139 	struct tps65910_platform_data *init_data;
140 	int ret = 0;
141 
142 	pmic_plat_data = dev_get_platdata(&i2c->dev);
143 	if (!pmic_plat_data)
144 		return -EINVAL;
145 
146 	init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL);
147 	if (init_data == NULL)
148 		return -ENOMEM;
149 
150 	tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
151 	if (tps65910 == NULL) {
152 		kfree(init_data);
153 		return -ENOMEM;
154 	}
155 
156 	i2c_set_clientdata(i2c, tps65910);
157 	tps65910->dev = &i2c->dev;
158 	tps65910->i2c_client = i2c;
159 	tps65910->id = id->driver_data;
160 	tps65910->read = tps65910_i2c_read;
161 	tps65910->write = tps65910_i2c_write;
162 	mutex_init(&tps65910->io_mutex);
163 
164 	ret = mfd_add_devices(tps65910->dev, -1,
165 			      tps65910s, ARRAY_SIZE(tps65910s),
166 			      NULL, 0);
167 	if (ret < 0)
168 		goto err;
169 
170 	init_data->irq = pmic_plat_data->irq;
171 	init_data->irq_base = pmic_plat_data->irq;
172 
173 	tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
174 
175 	ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
176 	if (ret < 0)
177 		goto err;
178 
179 	kfree(init_data);
180 	return ret;
181 
182 err:
183 	mfd_remove_devices(tps65910->dev);
184 	kfree(tps65910);
185 	kfree(init_data);
186 	return ret;
187 }
188 
189 static int tps65910_i2c_remove(struct i2c_client *i2c)
190 {
191 	struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
192 
193 	mfd_remove_devices(tps65910->dev);
194 	tps65910_irq_exit(tps65910);
195 	kfree(tps65910);
196 
197 	return 0;
198 }
199 
200 static const struct i2c_device_id tps65910_i2c_id[] = {
201        { "tps65910", TPS65910 },
202        { "tps65911", TPS65911 },
203        { }
204 };
205 MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id);
206 
207 
208 static struct i2c_driver tps65910_i2c_driver = {
209 	.driver = {
210 		   .name = "tps65910",
211 		   .owner = THIS_MODULE,
212 	},
213 	.probe = tps65910_i2c_probe,
214 	.remove = tps65910_i2c_remove,
215 	.id_table = tps65910_i2c_id,
216 };
217 
218 static int __init tps65910_i2c_init(void)
219 {
220 	return i2c_add_driver(&tps65910_i2c_driver);
221 }
222 /* init early so consumer devices can complete system boot */
223 subsys_initcall(tps65910_i2c_init);
224 
225 static void __exit tps65910_i2c_exit(void)
226 {
227 	i2c_del_driver(&tps65910_i2c_driver);
228 }
229 module_exit(tps65910_i2c_exit);
230 
231 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
232 MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
233 MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
234 MODULE_LICENSE("GPL");
235