Blame view

drivers/mfd/tps65217.c 6.51 KB
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * tps65217.c
   *
   * TPS65217 chip family multi-function driver
   *
   * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation version 2.
   *
   * This program is distributed "as is" WITHOUT ANY WARRANTY of any
   * kind, whether express or implied; without even the implied warranty
   * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   */
  
  #include <linux/kernel.h>
  #include <linux/device.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/init.h>
  #include <linux/i2c.h>
  #include <linux/slab.h>
  #include <linux/regmap.h>
  #include <linux/err.h>
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
27
28
  #include <linux/of.h>
  #include <linux/of_device.h>
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
29
30
31
  
  #include <linux/mfd/core.h>
  #include <linux/mfd/tps65217.h>
30fe2b5bd   Geert Uytterhoeven   mfd: ti: Constify...
32
  static const struct mfd_cell tps65217s[] = {
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
33
34
  	{
  		.name = "tps65217-pmic",
11d0d3009   Johannes Pointner   mfd: tps65217: Ad...
35
  		.of_compatible = "ti,tps65217-pmic",
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
36
  	},
b6290ffe1   Matthias Kaehlcke   mfd: Add backligh...
37
38
  	{
  		.name = "tps65217-bl",
11d0d3009   Johannes Pointner   mfd: tps65217: Ad...
39
  		.of_compatible = "ti,tps65217-bl",
b6290ffe1   Matthias Kaehlcke   mfd: Add backligh...
40
  	},
55cec67aa   Enric Balletbo i Serra   mfd: tps65217: Ad...
41
42
43
44
  	{
  		.name = "tps65217-charger",
  		.of_compatible = "ti,tps65217-charger",
  	},
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
45
  };
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  /**
   * tps65217_reg_read: Read a single tps65217 register.
   *
   * @tps: Device to read from.
   * @reg: Register to read.
   * @val: Contians the value
   */
  int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
  			unsigned int *val)
  {
  	return regmap_read(tps->regmap, reg, val);
  }
  EXPORT_SYMBOL_GPL(tps65217_reg_read);
  
  /**
   * tps65217_reg_write: Write a single tps65217 register.
   *
   * @tps65217: Device to write to.
   * @reg: Register to write to.
   * @val: Value to write.
   * @level: Password protected level
   */
  int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
  			unsigned int val, unsigned int level)
  {
  	int ret;
  	unsigned int xor_reg_val;
  
  	switch (level) {
  	case TPS65217_PROTECT_NONE:
  		return regmap_write(tps->regmap, reg, val);
  	case TPS65217_PROTECT_L1:
  		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
  		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
  							xor_reg_val);
  		if (ret < 0)
  			return ret;
  
  		return regmap_write(tps->regmap, reg, val);
  	case TPS65217_PROTECT_L2:
  		xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
  		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
  							xor_reg_val);
  		if (ret < 0)
  			return ret;
  		ret = regmap_write(tps->regmap, reg, val);
  		if (ret < 0)
  			return ret;
  		ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
  							xor_reg_val);
  		if (ret < 0)
  			return ret;
  		return regmap_write(tps->regmap, reg, val);
  	default:
  		return -EINVAL;
  	}
  }
  EXPORT_SYMBOL_GPL(tps65217_reg_write);
  
  /**
   * tps65217_update_bits: Modify bits w.r.t mask, val and level.
   *
   * @tps65217: Device to write to.
   * @reg: Register to read-write to.
   * @mask: Mask.
   * @val: Value to write.
   * @level: Password protected level
   */
27757e826   Mark Brown   mfd: Staticise no...
114
  static int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  		unsigned int mask, unsigned int val, unsigned int level)
  {
  	int ret;
  	unsigned int data;
  
  	ret = tps65217_reg_read(tps, reg, &data);
  	if (ret) {
  		dev_err(tps->dev, "Read from reg 0x%x failed
  ", reg);
  		return ret;
  	}
  
  	data &= ~mask;
  	data |= val & mask;
  
  	ret = tps65217_reg_write(tps, reg, data, level);
  	if (ret)
  		dev_err(tps->dev, "Write for reg 0x%x failed
  ", reg);
  
  	return ret;
  }
  
  int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
  		unsigned int mask, unsigned int val, unsigned int level)
  {
  	return tps65217_update_bits(tps, reg, mask, val, level);
  }
  EXPORT_SYMBOL_GPL(tps65217_set_bits);
  
  int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
  		unsigned int mask, unsigned int level)
  {
  	return tps65217_update_bits(tps, reg, mask, 0, level);
  }
  EXPORT_SYMBOL_GPL(tps65217_clear_bits);
af0a837de   Krzysztof Kozlowski   mfd: tps65217: Co...
151
  static const struct regmap_config tps65217_regmap_config = {
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
152
153
  	.reg_bits = 8,
  	.val_bits = 8,
0b496b4c9   Mark Brown   mfd: tps65217: Te...
154
155
  
  	.max_register = TPS65217_REG_MAX,
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
156
  };
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
157
158
159
160
  static const struct of_device_id tps65217_of_match[] = {
  	{ .compatible = "ti,tps65217", .data = (void *)TPS65217 },
  	{ /* sentinel */ },
  };
4895e493f   Javier Martinez Canillas   mfd: Export OF mo...
161
  MODULE_DEVICE_TABLE(of, tps65217_of_match);
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
162

f791be492   Bill Pemberton   mfd: remove use o...
163
  static int tps65217_probe(struct i2c_client *client,
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
164
165
166
  				const struct i2c_device_id *ids)
  {
  	struct tps65217 *tps;
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
167
  	unsigned int version;
5c6fbd56d   Lee Jones   mfd: tps65217: Na...
168
  	unsigned long chip_id = ids->driver_data;
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
169
  	const struct of_device_id *match;
eb433dad4   Colin Foe-Parker   mfd: tps65217: Se...
170
  	bool status_off = false;
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
171
  	int ret;
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
172

817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
173
174
175
176
177
178
179
180
  	if (client->dev.of_node) {
  		match = of_match_device(tps65217_of_match, &client->dev);
  		if (!match) {
  			dev_err(&client->dev,
  				"Failed to find matching dt id
  ");
  			return -EINVAL;
  		}
5c6fbd56d   Lee Jones   mfd: tps65217: Na...
181
  		chip_id = (unsigned long)match->data;
eb433dad4   Colin Foe-Parker   mfd: tps65217: Se...
182
183
  		status_off = of_property_read_bool(client->dev.of_node,
  					"ti,pmic-shutdown-controller");
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
184
185
186
187
188
189
190
  	}
  
  	if (!chip_id) {
  		dev_err(&client->dev, "id is null.
  ");
  		return -ENODEV;
  	}
a7f1b63eb   AnilKumar Ch   regulator: tps652...
191

d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
192
193
194
  	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
  	if (!tps)
  		return -ENOMEM;
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
195
196
197
  	i2c_set_clientdata(client, tps);
  	tps->dev = &client->dev;
  	tps->id = chip_id;
0ef4619c7   Axel Lin   mfd: Convert tps6...
198
  	tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config);
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
199
200
201
202
203
204
205
  	if (IS_ERR(tps->regmap)) {
  		ret = PTR_ERR(tps->regmap);
  		dev_err(tps->dev, "Failed to allocate register map: %d
  ",
  			ret);
  		return ret;
  	}
b89b6b6bc   Laxman Dewangan   mfd: tps65217: Us...
206
207
  	ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
  				   ARRAY_SIZE(tps65217s), NULL, 0, NULL);
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
208
209
210
211
212
  	if (ret < 0) {
  		dev_err(tps->dev, "mfd_add_devices failed: %d
  ", ret);
  		return ret;
  	}
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
213
214
215
  
  	ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
  	if (ret < 0) {
0ef4619c7   Axel Lin   mfd: Convert tps6...
216
217
218
219
  		dev_err(tps->dev, "Failed to read revision register: %d
  ",
  			ret);
  		return ret;
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
220
  	}
eb433dad4   Colin Foe-Parker   mfd: tps65217: Se...
221
222
223
224
225
226
227
228
229
  	/* Set the PMIC to shutdown on PWR_EN toggle */
  	if (status_off) {
  		ret = tps65217_set_bits(tps, TPS65217_REG_STATUS,
  				TPS65217_STATUS_OFF, TPS65217_STATUS_OFF,
  				TPS65217_PROTECT_NONE);
  		if (ret)
  			dev_warn(tps->dev, "unable to set the status OFF
  ");
  	}
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
230
231
232
233
  	dev_info(tps->dev, "TPS65217 ID %#x version 1.%d
  ",
  			(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
  			version & TPS65217_CHIPID_REV_MASK);
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
234
  	return 0;
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
235
  }
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
236
  static const struct i2c_device_id tps65217_id_table[] = {
817bb7fbf   AnilKumar Ch   mfd: Move tps6521...
237
238
  	{"tps65217", TPS65217},
  	{ /* sentinel */ }
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
239
240
241
242
243
244
  };
  MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
  
  static struct i2c_driver tps65217_driver = {
  	.driver		= {
  		.name	= "tps65217",
a351451ac   Sachin Kamat   mfd: tps65217: Re...
245
  		.of_match_table = tps65217_of_match,
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
246
247
248
  	},
  	.id_table	= tps65217_id_table,
  	.probe		= tps65217_probe,
d48f411c1   AnilKumar Ch   mfd: Add new mfd ...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  };
  
  static int __init tps65217_init(void)
  {
  	return i2c_add_driver(&tps65217_driver);
  }
  subsys_initcall(tps65217_init);
  
  static void __exit tps65217_exit(void)
  {
  	i2c_del_driver(&tps65217_driver);
  }
  module_exit(tps65217_exit);
  
  MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
  MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
  MODULE_LICENSE("GPL v2");