Blame view

drivers/mfd/tc3589x.c 11.8 KB
1f67b599f   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
2
3
4
  /*
   * Copyright (C) ST-Ericsson SA 2010
   *
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
5
6
7
8
9
10
11
   * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
   * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
   */
  
  #include <linux/module.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
15e27b108   Lee Jones   mfd: Provide the ...
12
  #include <linux/irqdomain.h>
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
13
14
  #include <linux/slab.h>
  #include <linux/i2c.h>
a435ae1d5   Lee Jones   mfd: Enable the t...
15
  #include <linux/of.h>
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
16
  #include <linux/of_device.h>
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
17
  #include <linux/mfd/core.h>
c6eda6c5e   Sundar Iyer   mfd/tc35892: rena...
18
  #include <linux/mfd/tc3589x.h>
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
19
  #include <linux/err.h>
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
20

e64c1eb47   Linus Walleij   mfd: tc3589x: Det...
21
22
23
24
25
26
27
28
29
30
31
32
  /**
   * enum tc3589x_version - indicates the TC3589x version
   */
  enum tc3589x_version {
  	TC3589X_TC35890,
  	TC3589X_TC35892,
  	TC3589X_TC35893,
  	TC3589X_TC35894,
  	TC3589X_TC35895,
  	TC3589X_TC35896,
  	TC3589X_UNKNOWN,
  };
593e9d70f   Sundar Iyer   mfd/tc3589x: add ...
33
34
  #define TC3589x_CLKMODE_MODCTL_SLEEP		0x0
  #define TC3589x_CLKMODE_MODCTL_OPERATION	(1 << 0)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
35
  /**
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
36
37
   * tc3589x_reg_read() - read a single TC3589x register
   * @tc3589x:	Device to read from
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
38
39
   * @reg:	Register to read
   */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
40
  int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
41
42
  {
  	int ret;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
43
  	ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
44
  	if (ret < 0)
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
45
46
  		dev_err(tc3589x->dev, "failed to read reg %#x: %d
  ",
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
47
48
49
50
  			reg, ret);
  
  	return ret;
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
51
  EXPORT_SYMBOL_GPL(tc3589x_reg_read);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
52
53
  
  /**
d87814a3e   Julia Lawall   mfd: tc3589x: Imp...
54
   * tc3589x_reg_write() - write a single TC3589x register
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
55
   * @tc3589x:	Device to write to
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
56
57
58
   * @reg:	Register to read
   * @data:	Value to write
   */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
59
  int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
60
61
  {
  	int ret;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
62
  	ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
63
  	if (ret < 0)
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
64
65
  		dev_err(tc3589x->dev, "failed to write reg %#x: %d
  ",
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
66
67
68
69
  			reg, ret);
  
  	return ret;
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
70
  EXPORT_SYMBOL_GPL(tc3589x_reg_write);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
71
72
  
  /**
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
73
74
   * tc3589x_block_read() - read multiple TC3589x registers
   * @tc3589x:	Device to read from
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
75
76
77
78
   * @reg:	First register
   * @length:	Number of registers
   * @values:	Buffer to write to
   */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
79
  int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
80
81
  {
  	int ret;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
82
  	ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
83
  	if (ret < 0)
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
84
85
  		dev_err(tc3589x->dev, "failed to read regs %#x: %d
  ",
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
86
87
88
89
  			reg, ret);
  
  	return ret;
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
90
  EXPORT_SYMBOL_GPL(tc3589x_block_read);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
91
92
  
  /**
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
93
94
   * tc3589x_block_write() - write multiple TC3589x registers
   * @tc3589x:	Device to write to
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
95
96
97
98
   * @reg:	First register
   * @length:	Number of registers
   * @values:	Values to write
   */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
99
  int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
100
101
102
  			const u8 *values)
  {
  	int ret;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
103
  	ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length,
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
104
105
  					     values);
  	if (ret < 0)
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
106
107
  		dev_err(tc3589x->dev, "failed to write regs %#x: %d
  ",
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
108
109
110
111
  			reg, ret);
  
  	return ret;
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
112
  EXPORT_SYMBOL_GPL(tc3589x_block_write);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
113
114
  
  /**
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
115
116
   * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register
   * @tc3589x:	Device to write to
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
117
118
   * @reg:	Register to write
   * @mask:	Mask of bits to set
d87814a3e   Julia Lawall   mfd: tc3589x: Imp...
119
   * @val:	Value to set
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
120
   */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
121
  int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
122
123
  {
  	int ret;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
124
  	mutex_lock(&tc3589x->lock);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
125

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
126
  	ret = tc3589x_reg_read(tc3589x, reg);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
127
128
129
130
131
  	if (ret < 0)
  		goto out;
  
  	ret &= ~mask;
  	ret |= val;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
132
  	ret = tc3589x_reg_write(tc3589x, reg, ret);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
133
134
  
  out:
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
135
  	mutex_unlock(&tc3589x->lock);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
136
137
  	return ret;
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
138
  EXPORT_SYMBOL_GPL(tc3589x_set_bits);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
139
140
141
  
  static struct resource gpio_resources[] = {
  	{
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
142
143
  		.start	= TC3589x_INT_GPIIRQ,
  		.end	= TC3589x_INT_GPIIRQ,
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
144
145
146
  		.flags	= IORESOURCE_IRQ,
  	},
  };
09c730a48   Sundar Iyer   input/tc3589x: ad...
147
148
149
150
151
152
153
  static struct resource keypad_resources[] = {
  	{
  		.start  = TC3589x_INT_KBDIRQ,
  		.end    = TC3589x_INT_KBDIRQ,
  		.flags  = IORESOURCE_IRQ,
  	},
  };
afb580a94   Geert Uytterhoeven   mfd: toshiba: Con...
154
  static const struct mfd_cell tc3589x_dev_gpio[] = {
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
155
  	{
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
156
  		.name		= "tc3589x-gpio",
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
157
158
  		.num_resources	= ARRAY_SIZE(gpio_resources),
  		.resources	= &gpio_resources[0],
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
159
  		.of_compatible	= "toshiba,tc3589x-gpio",
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
160
161
  	},
  };
afb580a94   Geert Uytterhoeven   mfd: toshiba: Con...
162
  static const struct mfd_cell tc3589x_dev_keypad[] = {
09c730a48   Sundar Iyer   input/tc3589x: ad...
163
164
165
166
  	{
  		.name           = "tc3589x-keypad",
  		.num_resources  = ARRAY_SIZE(keypad_resources),
  		.resources      = &keypad_resources[0],
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
167
  		.of_compatible	= "toshiba,tc3589x-keypad",
09c730a48   Sundar Iyer   input/tc3589x: ad...
168
169
  	},
  };
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
170
  static irqreturn_t tc3589x_irq(int irq, void *data)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
171
  {
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
172
  	struct tc3589x *tc3589x = data;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
173
  	int status;
bd77efd0c   Sundar Iyer   mfd/tc3589x: fix ...
174
  again:
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
175
  	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
176
177
178
179
180
  	if (status < 0)
  		return IRQ_NONE;
  
  	while (status) {
  		int bit = __ffs(status);
15e27b108   Lee Jones   mfd: Provide the ...
181
  		int virq = irq_create_mapping(tc3589x->domain, bit);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
182

15e27b108   Lee Jones   mfd: Provide the ...
183
  		handle_nested_irq(virq);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
184
185
186
187
188
189
  		status &= ~(1 << bit);
  	}
  
  	/*
  	 * A dummy read or write (to any register) appears to be necessary to
  	 * have the last interrupt clear (for example, GPIO IC write) take
bd77efd0c   Sundar Iyer   mfd/tc3589x: fix ...
190
191
  	 * effect. In such a case, recheck for any interrupt which is still
  	 * pending.
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
192
  	 */
bd77efd0c   Sundar Iyer   mfd/tc3589x: fix ...
193
194
195
  	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
  	if (status)
  		goto again;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
196
197
198
  
  	return IRQ_HANDLED;
  }
15e27b108   Lee Jones   mfd: Provide the ...
199
200
  static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq,
  				irq_hw_number_t hwirq)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
201
  {
15e27b108   Lee Jones   mfd: Provide the ...
202
  	struct tc3589x *tc3589x = d->host_data;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
203

15e27b108   Lee Jones   mfd: Provide the ...
204
205
206
207
  	irq_set_chip_data(virq, tc3589x);
  	irq_set_chip_and_handler(virq, &dummy_irq_chip,
  				handle_edge_irq);
  	irq_set_nested_thread(virq, 1);
15e27b108   Lee Jones   mfd: Provide the ...
208
  	irq_set_noprobe(virq);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
209
210
211
  
  	return 0;
  }
15e27b108   Lee Jones   mfd: Provide the ...
212
  static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
213
  {
15e27b108   Lee Jones   mfd: Provide the ...
214
215
216
  	irq_set_chip_and_handler(virq, NULL, NULL);
  	irq_set_chip_data(virq, NULL);
  }
7ce7b26f8   Krzysztof Kozlowski   mfd: Constify reg...
217
  static const struct irq_domain_ops tc3589x_irq_ops = {
1f0529b4d   Linus Walleij   mfd: tc3589x: Use...
218
  	.map    = tc3589x_irq_map,
15e27b108   Lee Jones   mfd: Provide the ...
219
  	.unmap  = tc3589x_irq_unmap,
627918ed1   Linus Walleij   mfd: tc3589x: Tra...
220
  	.xlate  = irq_domain_xlate_onecell,
15e27b108   Lee Jones   mfd: Provide the ...
221
  };
a435ae1d5   Lee Jones   mfd: Enable the t...
222
  static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
15e27b108   Lee Jones   mfd: Provide the ...
223
  {
1f0529b4d   Linus Walleij   mfd: tc3589x: Use...
224
  	tc3589x->domain = irq_domain_add_simple(
90f2d0f7b   Linus Walleij   mfd: tc3589x: get...
225
  		np, TC3589x_NR_INTERNAL_IRQS, 0,
1f0529b4d   Linus Walleij   mfd: tc3589x: Use...
226
  		&tc3589x_irq_ops, tc3589x);
15e27b108   Lee Jones   mfd: Provide the ...
227
228
229
230
231
232
233
234
  
  	if (!tc3589x->domain) {
  		dev_err(tc3589x->dev, "Failed to create irqdomain
  ");
  		return -ENOSYS;
  	}
  
  	return 0;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
235
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
236
  static int tc3589x_chip_init(struct tc3589x *tc3589x)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
237
238
  {
  	int manf, ver, ret;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
239
  	manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
240
241
  	if (manf < 0)
  		return manf;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
242
  	ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
243
244
  	if (ver < 0)
  		return ver;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
245
246
247
  	if (manf != TC3589x_MANFCODE_MAGIC) {
  		dev_err(tc3589x->dev, "unknown manufacturer: %#x
  ", manf);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
248
249
  		return -EINVAL;
  	}
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
250
251
  	dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x
  ", manf, ver);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
252

523bc3820   Sundar Iyer   mfd/tc3589x: undo...
253
254
255
256
257
  	/*
  	 * Put everything except the IRQ module into reset;
  	 * also spare the GPIO module for any pin initialization
  	 * done during pre-kernel boot
  	 */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
258
259
260
  	ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
  				TC3589x_RSTCTRL_TIMRST
  				| TC3589x_RSTCTRL_ROTRST
523bc3820   Sundar Iyer   mfd/tc3589x: undo...
261
  				| TC3589x_RSTCTRL_KBDRST);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
262
263
264
265
  	if (ret < 0)
  		return ret;
  
  	/* Clear the reset interrupt. */
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
266
  	return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
267
  }
f791be492   Bill Pemberton   mfd: remove use o...
268
  static int tc3589x_device_init(struct tc3589x *tc3589x)
611b7590a   Sundar Iyer   mfd/tc3589x: add ...
269
270
271
272
273
274
  {
  	int ret = 0;
  	unsigned int blocks = tc3589x->pdata->block;
  
  	if (blocks & TC3589x_BLOCK_GPIO) {
  		ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
55692af5e   Mark Brown   mfd: core: Push i...
275
  				      ARRAY_SIZE(tc3589x_dev_gpio), NULL,
90f2d0f7b   Linus Walleij   mfd: tc3589x: get...
276
  				      0, tc3589x->domain);
611b7590a   Sundar Iyer   mfd/tc3589x: add ...
277
278
279
280
281
282
283
284
  		if (ret) {
  			dev_err(tc3589x->dev, "failed to add gpio child
  ");
  			return ret;
  		}
  		dev_info(tc3589x->dev, "added gpio block
  ");
  	}
09c730a48   Sundar Iyer   input/tc3589x: ad...
285
286
  	if (blocks & TC3589x_BLOCK_KEYPAD) {
  		ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
55692af5e   Mark Brown   mfd: core: Push i...
287
  				      ARRAY_SIZE(tc3589x_dev_keypad), NULL,
90f2d0f7b   Linus Walleij   mfd: tc3589x: get...
288
  				      0, tc3589x->domain);
09c730a48   Sundar Iyer   input/tc3589x: ad...
289
290
291
292
293
294
295
296
  		if (ret) {
  			dev_err(tc3589x->dev, "failed to keypad child
  ");
  			return ret;
  		}
  		dev_info(tc3589x->dev, "added keypad block
  ");
  	}
611b7590a   Sundar Iyer   mfd/tc3589x: add ...
297

09c730a48   Sundar Iyer   input/tc3589x: ad...
298
  	return ret;
611b7590a   Sundar Iyer   mfd/tc3589x: add ...
299
  }
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  static const struct of_device_id tc3589x_match[] = {
  	/* Legacy compatible string */
  	{ .compatible = "tc3589x", .data = (void *) TC3589X_UNKNOWN },
  	{ .compatible = "toshiba,tc35890", .data = (void *) TC3589X_TC35890 },
  	{ .compatible = "toshiba,tc35892", .data = (void *) TC3589X_TC35892 },
  	{ .compatible = "toshiba,tc35893", .data = (void *) TC3589X_TC35893 },
  	{ .compatible = "toshiba,tc35894", .data = (void *) TC3589X_TC35894 },
  	{ .compatible = "toshiba,tc35895", .data = (void *) TC3589X_TC35895 },
  	{ .compatible = "toshiba,tc35896", .data = (void *) TC3589X_TC35896 },
  	{ }
  };
  
  MODULE_DEVICE_TABLE(of, tc3589x_match);
  
  static struct tc3589x_platform_data *
  tc3589x_of_probe(struct device *dev, enum tc3589x_version *version)
a435ae1d5   Lee Jones   mfd: Enable the t...
316
  {
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
317
318
  	struct device_node *np = dev->of_node;
  	struct tc3589x_platform_data *pdata;
a435ae1d5   Lee Jones   mfd: Enable the t...
319
  	struct device_node *child;
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
320
321
322
323
324
325
326
327
328
329
  	const struct of_device_id *of_id;
  
  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
  	if (!pdata)
  		return ERR_PTR(-ENOMEM);
  
  	of_id = of_match_device(tc3589x_match, dev);
  	if (!of_id)
  		return ERR_PTR(-ENODEV);
  	*version = (enum tc3589x_version) of_id->data;
a435ae1d5   Lee Jones   mfd: Enable the t...
330
331
  
  	for_each_child_of_node(np, child) {
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
332
  		if (of_device_is_compatible(child, "toshiba,tc3589x-gpio"))
a435ae1d5   Lee Jones   mfd: Enable the t...
333
  			pdata->block |= TC3589x_BLOCK_GPIO;
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
334
  		if (of_device_is_compatible(child, "toshiba,tc3589x-keypad"))
a435ae1d5   Lee Jones   mfd: Enable the t...
335
  			pdata->block |= TC3589x_BLOCK_KEYPAD;
a435ae1d5   Lee Jones   mfd: Enable the t...
336
  	}
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
337
  	return pdata;
a435ae1d5   Lee Jones   mfd: Enable the t...
338
  }
f791be492   Bill Pemberton   mfd: remove use o...
339
  static int tc3589x_probe(struct i2c_client *i2c,
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
340
341
  				   const struct i2c_device_id *id)
  {
a435ae1d5   Lee Jones   mfd: Enable the t...
342
  	struct device_node *np = i2c->dev.of_node;
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
343
  	struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
344
  	struct tc3589x *tc3589x;
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
345
  	enum tc3589x_version version;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
346
  	int ret;
a435ae1d5   Lee Jones   mfd: Enable the t...
347
  	if (!pdata) {
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
348
349
  		pdata = tc3589x_of_probe(&i2c->dev, &version);
  		if (IS_ERR(pdata)) {
a435ae1d5   Lee Jones   mfd: Enable the t...
350
351
  			dev_err(&i2c->dev, "No platform data or DT found
  ");
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
352
  			return PTR_ERR(pdata);
a435ae1d5   Lee Jones   mfd: Enable the t...
353
  		}
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
354
355
356
  	} else {
  		/* When not probing from device tree we have this ID */
  		version = id->driver_data;
a435ae1d5   Lee Jones   mfd: Enable the t...
357
  	}
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
358
359
360
  	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
  				     | I2C_FUNC_SMBUS_I2C_BLOCK))
  		return -EIO;
1383e00f7   Jingoo Han   mfd: tc3589x: Use...
361
362
  	tc3589x = devm_kzalloc(&i2c->dev, sizeof(struct tc3589x),
  				GFP_KERNEL);
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
363
  	if (!tc3589x)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
364
  		return -ENOMEM;
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
365
  	mutex_init(&tc3589x->lock);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
366

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
367
368
369
  	tc3589x->dev = &i2c->dev;
  	tc3589x->i2c = i2c;
  	tc3589x->pdata = pdata;
e64c1eb47   Linus Walleij   mfd: tc3589x: Det...
370

a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
371
  	switch (version) {
e64c1eb47   Linus Walleij   mfd: tc3589x: Det...
372
373
374
375
376
377
378
379
380
381
382
383
384
  	case TC3589X_TC35893:
  	case TC3589X_TC35895:
  	case TC3589X_TC35896:
  		tc3589x->num_gpio = 20;
  		break;
  	case TC3589X_TC35890:
  	case TC3589X_TC35892:
  	case TC3589X_TC35894:
  	case TC3589X_UNKNOWN:
  	default:
  		tc3589x->num_gpio = 24;
  		break;
  	}
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
385

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
386
  	i2c_set_clientdata(i2c, tc3589x);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
387

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
388
  	ret = tc3589x_chip_init(tc3589x);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
389
  	if (ret)
1383e00f7   Jingoo Han   mfd: tc3589x: Use...
390
  		return ret;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
391

a435ae1d5   Lee Jones   mfd: Enable the t...
392
  	ret = tc3589x_irq_init(tc3589x, np);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
393
  	if (ret)
1383e00f7   Jingoo Han   mfd: tc3589x: Use...
394
  		return ret;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
395

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
396
  	ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
397
  				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
398
  				   "tc3589x", tc3589x);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
399
  	if (ret) {
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
400
401
  		dev_err(tc3589x->dev, "failed to request IRQ: %d
  ", ret);
1383e00f7   Jingoo Han   mfd: tc3589x: Use...
402
  		return ret;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
403
  	}
611b7590a   Sundar Iyer   mfd/tc3589x: add ...
404
  	ret = tc3589x_device_init(tc3589x);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
405
  	if (ret) {
611b7590a   Sundar Iyer   mfd/tc3589x: add ...
406
407
  		dev_err(tc3589x->dev, "failed to add child devices
  ");
1383e00f7   Jingoo Han   mfd: tc3589x: Use...
408
  		return ret;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
409
410
411
  	}
  
  	return 0;
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
412
  }
4740f73fe   Bill Pemberton   mfd: remove use o...
413
  static int tc3589x_remove(struct i2c_client *client)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
414
  {
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
415
  	struct tc3589x *tc3589x = i2c_get_clientdata(client);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
416

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
417
  	mfd_remove_devices(tc3589x->dev);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
418

b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
419
420
  	return 0;
  }
930bf0229   Axel Lin   mfd: Guard tc3589...
421
  #ifdef CONFIG_PM_SLEEP
593e9d70f   Sundar Iyer   mfd/tc3589x: add ...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  static int tc3589x_suspend(struct device *dev)
  {
  	struct tc3589x *tc3589x = dev_get_drvdata(dev);
  	struct i2c_client *client = tc3589x->i2c;
  	int ret = 0;
  
  	/* put the system to sleep mode */
  	if (!device_may_wakeup(&client->dev))
  		ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
  				TC3589x_CLKMODE_MODCTL_SLEEP);
  
  	return ret;
  }
  
  static int tc3589x_resume(struct device *dev)
  {
  	struct tc3589x *tc3589x = dev_get_drvdata(dev);
  	struct i2c_client *client = tc3589x->i2c;
  	int ret = 0;
  
  	/* enable the system into operation */
  	if (!device_may_wakeup(&client->dev))
  		ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
  				TC3589x_CLKMODE_MODCTL_OPERATION);
  
  	return ret;
  }
54d8e2c32   Linus Walleij   mfd: Add missing ...
449
  #endif
593e9d70f   Sundar Iyer   mfd/tc3589x: add ...
450

930bf0229   Axel Lin   mfd: Guard tc3589...
451
  static SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, tc3589x_resume);
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
452
  static const struct i2c_device_id tc3589x_id[] = {
e64c1eb47   Linus Walleij   mfd: tc3589x: Det...
453
454
455
456
457
458
459
  	{ "tc35890", TC3589X_TC35890 },
  	{ "tc35892", TC3589X_TC35892 },
  	{ "tc35893", TC3589X_TC35893 },
  	{ "tc35894", TC3589X_TC35894 },
  	{ "tc35895", TC3589X_TC35895 },
  	{ "tc35896", TC3589X_TC35896 },
  	{ "tc3589x", TC3589X_UNKNOWN },
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
460
461
  	{ }
  };
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
462
  MODULE_DEVICE_TABLE(i2c, tc3589x_id);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
463

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
464
  static struct i2c_driver tc3589x_driver = {
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
465
466
  	.driver = {
  		.name	= "tc3589x",
a381b13e2   Linus Walleij   mfd: tc3589x: Ref...
467
468
469
  		.pm	= &tc3589x_dev_pm_ops,
  		.of_match_table = of_match_ptr(tc3589x_match),
  	},
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
470
  	.probe		= tc3589x_probe,
84449216b   Bill Pemberton   mfd: remove use o...
471
  	.remove		= tc3589x_remove,
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
472
  	.id_table	= tc3589x_id,
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
473
  };
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
474
  static int __init tc3589x_init(void)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
475
  {
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
476
  	return i2c_add_driver(&tc3589x_driver);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
477
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
478
  subsys_initcall(tc3589x_init);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
479

20406ebff   Sundar Iyer   mfd/tc3589x: rena...
480
  static void __exit tc3589x_exit(void)
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
481
  {
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
482
  	i2c_del_driver(&tc3589x_driver);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
483
  }
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
484
  module_exit(tc3589x_exit);
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
485
486
  
  MODULE_LICENSE("GPL v2");
20406ebff   Sundar Iyer   mfd/tc3589x: rena...
487
  MODULE_DESCRIPTION("TC3589x MFD core driver");
b4ecd326b   Rabin Vincent   mfd: Add Toshiba'...
488
  MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");