Blame view

drivers/mfd/menelaus.c 29.3 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Copyright (C) 2004 Texas Instruments, Inc.
   *
   * Some parts based tps65010.c:
   * Copyright (C) 2004 Texas Instruments and
   * Copyright (C) 2004-2005 David Brownell
   *
   * Some parts based on tlv320aic24.c:
   * Copyright (C) by Kai Svahn <kai.svahn@nokia.com>
   *
   * Changes for interrupt handling and clean-up by
   * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
   * Cleanup and generalized support for voltage setting by
   * Juha Yrjola
   * Added support for controlling VCORE and regulator sleep states,
   * Amit Kucheria <amit.kucheria@nokia.com>
   * Copyright (C) 2005, 2006 Nokia Corporation
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
19
20
21
22
23
24
25
26
27
28
29
   */
  
  #include <linux/module.h>
  #include <linux/i2c.h>
  #include <linux/interrupt.h>
  #include <linux/sched.h>
  #include <linux/mutex.h>
  #include <linux/workqueue.h>
  #include <linux/delay.h>
  #include <linux/rtc.h>
  #include <linux/bcd.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
30
  #include <linux/slab.h>
7bd3b6185   Tony Lindgren   ARM: OMAP2: Move ...
31
  #include <linux/mfd/menelaus.h>
288e6eaa0   Bjorn Helgaas   gpio: Include lin...
32
  #include <linux/gpio.h>
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
33

0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
34
  #include <asm/mach/irq.h>
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
35
36
  
  #define DRIVER_NAME			"menelaus"
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
37
38
39
40
41
42
43
44
45
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
114
  #define MENELAUS_I2C_ADDRESS		0x72
  
  #define MENELAUS_REV			0x01
  #define MENELAUS_VCORE_CTRL1		0x02
  #define MENELAUS_VCORE_CTRL2		0x03
  #define MENELAUS_VCORE_CTRL3		0x04
  #define MENELAUS_VCORE_CTRL4		0x05
  #define MENELAUS_VCORE_CTRL5		0x06
  #define MENELAUS_DCDC_CTRL1		0x07
  #define MENELAUS_DCDC_CTRL2		0x08
  #define MENELAUS_DCDC_CTRL3		0x09
  #define MENELAUS_LDO_CTRL1		0x0A
  #define MENELAUS_LDO_CTRL2		0x0B
  #define MENELAUS_LDO_CTRL3		0x0C
  #define MENELAUS_LDO_CTRL4		0x0D
  #define MENELAUS_LDO_CTRL5		0x0E
  #define MENELAUS_LDO_CTRL6		0x0F
  #define MENELAUS_LDO_CTRL7		0x10
  #define MENELAUS_LDO_CTRL8		0x11
  #define MENELAUS_SLEEP_CTRL1		0x12
  #define MENELAUS_SLEEP_CTRL2		0x13
  #define MENELAUS_DEVICE_OFF		0x14
  #define MENELAUS_OSC_CTRL		0x15
  #define MENELAUS_DETECT_CTRL		0x16
  #define MENELAUS_INT_MASK1		0x17
  #define MENELAUS_INT_MASK2		0x18
  #define MENELAUS_INT_STATUS1		0x19
  #define MENELAUS_INT_STATUS2		0x1A
  #define MENELAUS_INT_ACK1		0x1B
  #define MENELAUS_INT_ACK2		0x1C
  #define MENELAUS_GPIO_CTRL		0x1D
  #define MENELAUS_GPIO_IN		0x1E
  #define MENELAUS_GPIO_OUT		0x1F
  #define MENELAUS_BBSMS			0x20
  #define MENELAUS_RTC_CTRL		0x21
  #define MENELAUS_RTC_UPDATE		0x22
  #define MENELAUS_RTC_SEC		0x23
  #define MENELAUS_RTC_MIN		0x24
  #define MENELAUS_RTC_HR			0x25
  #define MENELAUS_RTC_DAY		0x26
  #define MENELAUS_RTC_MON		0x27
  #define MENELAUS_RTC_YR			0x28
  #define MENELAUS_RTC_WKDAY		0x29
  #define MENELAUS_RTC_AL_SEC		0x2A
  #define MENELAUS_RTC_AL_MIN		0x2B
  #define MENELAUS_RTC_AL_HR		0x2C
  #define MENELAUS_RTC_AL_DAY		0x2D
  #define MENELAUS_RTC_AL_MON		0x2E
  #define MENELAUS_RTC_AL_YR		0x2F
  #define MENELAUS_RTC_COMP_MSB		0x30
  #define MENELAUS_RTC_COMP_LSB		0x31
  #define MENELAUS_S1_PULL_EN		0x32
  #define MENELAUS_S1_PULL_DIR		0x33
  #define MENELAUS_S2_PULL_EN		0x34
  #define MENELAUS_S2_PULL_DIR		0x35
  #define MENELAUS_MCT_CTRL1		0x36
  #define MENELAUS_MCT_CTRL2		0x37
  #define MENELAUS_MCT_CTRL3		0x38
  #define MENELAUS_MCT_PIN_ST		0x39
  #define MENELAUS_DEBOUNCE1		0x3A
  
  #define IH_MENELAUS_IRQS		12
  #define MENELAUS_MMC_S1CD_IRQ		0	/* MMC slot 1 card change */
  #define MENELAUS_MMC_S2CD_IRQ		1	/* MMC slot 2 card change */
  #define MENELAUS_MMC_S1D1_IRQ		2	/* MMC DAT1 low in slot 1 */
  #define MENELAUS_MMC_S2D1_IRQ		3	/* MMC DAT1 low in slot 2 */
  #define MENELAUS_LOWBAT_IRQ		4	/* Low battery */
  #define MENELAUS_HOTDIE_IRQ		5	/* Hot die detect */
  #define MENELAUS_UVLO_IRQ		6	/* UVLO detect */
  #define MENELAUS_TSHUT_IRQ		7	/* Thermal shutdown */
  #define MENELAUS_RTCTMR_IRQ		8	/* RTC timer */
  #define MENELAUS_RTCALM_IRQ		9	/* RTC alarm */
  #define MENELAUS_RTCERR_IRQ		10	/* RTC error */
  #define MENELAUS_PSHBTN_IRQ		11	/* Push button */
  #define MENELAUS_RESERVED12_IRQ		12	/* Reserved */
  #define MENELAUS_RESERVED13_IRQ		13	/* Reserved */
  #define MENELAUS_RESERVED14_IRQ		14	/* Reserved */
  #define MENELAUS_RESERVED15_IRQ		15	/* Reserved */
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
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
  /* VCORE_CTRL1 register */
  #define VCORE_CTRL1_BYP_COMP		(1 << 5)
  #define VCORE_CTRL1_HW_NSW		(1 << 7)
  
  /* GPIO_CTRL register */
  #define GPIO_CTRL_SLOTSELEN		(1 << 5)
  #define GPIO_CTRL_SLPCTLEN		(1 << 6)
  #define GPIO1_DIR_INPUT			(1 << 0)
  #define GPIO2_DIR_INPUT			(1 << 1)
  #define GPIO3_DIR_INPUT			(1 << 2)
  
  /* MCT_CTRL1 register */
  #define MCT_CTRL1_S1_CMD_OD		(1 << 2)
  #define MCT_CTRL1_S2_CMD_OD		(1 << 3)
  
  /* MCT_CTRL2 register */
  #define MCT_CTRL2_VS2_SEL_D0		(1 << 0)
  #define MCT_CTRL2_VS2_SEL_D1		(1 << 1)
  #define MCT_CTRL2_S1CD_BUFEN		(1 << 4)
  #define MCT_CTRL2_S2CD_BUFEN		(1 << 5)
  #define MCT_CTRL2_S1CD_DBEN		(1 << 6)
  #define MCT_CTRL2_S2CD_BEN		(1 << 7)
  
  /* MCT_CTRL3 register */
  #define MCT_CTRL3_SLOT1_EN		(1 << 0)
  #define MCT_CTRL3_SLOT2_EN		(1 << 1)
  #define MCT_CTRL3_S1_AUTO_EN		(1 << 2)
  #define MCT_CTRL3_S2_AUTO_EN		(1 << 3)
  
  /* MCT_PIN_ST register */
  #define MCT_PIN_ST_S1_CD_ST		(1 << 0)
  #define MCT_PIN_ST_S2_CD_ST		(1 << 1)
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  static void menelaus_work(struct work_struct *_menelaus);
  
  struct menelaus_chip {
  	struct mutex		lock;
  	struct i2c_client	*client;
  	struct work_struct	work;
  #ifdef CONFIG_RTC_DRV_TWL92330
  	struct rtc_device	*rtc;
  	u8			rtc_control;
  	unsigned		uie:1;
  #endif
  	unsigned		vcore_hw_mode:1;
  	u8			mask1, mask2;
  	void			(*handlers[16])(struct menelaus_chip *);
  	void			(*mmc_callback)(void *data, u8 mask);
  	void			*mmc_callback_data;
  };
  
  static struct menelaus_chip *the_menelaus;
  
  static int menelaus_write_reg(int reg, u8 value)
  {
  	int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value);
  
  	if (val < 0) {
1f7c8234c   Emil Medve   Make the pr_*() f...
172
  		pr_err(DRIVER_NAME ": write error");
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
173
174
175
176
177
178
179
180
181
182
183
  		return val;
  	}
  
  	return 0;
  }
  
  static int menelaus_read_reg(int reg)
  {
  	int val = i2c_smbus_read_byte_data(the_menelaus->client, reg);
  
  	if (val < 0)
1f7c8234c   Emil Medve   Make the pr_*() f...
184
  		pr_err(DRIVER_NAME ": read error");
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  
  	return val;
  }
  
  static int menelaus_enable_irq(int irq)
  {
  	if (irq > 7) {
  		irq -= 8;
  		the_menelaus->mask2 &= ~(1 << irq);
  		return menelaus_write_reg(MENELAUS_INT_MASK2,
  				the_menelaus->mask2);
  	} else {
  		the_menelaus->mask1 &= ~(1 << irq);
  		return menelaus_write_reg(MENELAUS_INT_MASK1,
  				the_menelaus->mask1);
  	}
  }
  
  static int menelaus_disable_irq(int irq)
  {
  	if (irq > 7) {
  		irq -= 8;
  		the_menelaus->mask2 |= (1 << irq);
  		return menelaus_write_reg(MENELAUS_INT_MASK2,
  				the_menelaus->mask2);
  	} else {
  		the_menelaus->mask1 |= (1 << irq);
  		return menelaus_write_reg(MENELAUS_INT_MASK1,
  				the_menelaus->mask1);
  	}
  }
  
  static int menelaus_ack_irq(int irq)
  {
  	if (irq > 7)
  		return menelaus_write_reg(MENELAUS_INT_ACK2, 1 << (irq - 8));
  	else
  		return menelaus_write_reg(MENELAUS_INT_ACK1, 1 << irq);
  }
  
  /* Adds a handler for an interrupt. Does not run in interrupt context */
  static int menelaus_add_irq_work(int irq,
  		void (*handler)(struct menelaus_chip *))
  {
  	int ret = 0;
  
  	mutex_lock(&the_menelaus->lock);
  	the_menelaus->handlers[irq] = handler;
  	ret = menelaus_enable_irq(irq);
  	mutex_unlock(&the_menelaus->lock);
  
  	return ret;
  }
  
  /* Removes handler for an interrupt */
  static int menelaus_remove_irq_work(int irq)
  {
  	int ret = 0;
  
  	mutex_lock(&the_menelaus->lock);
  	ret = menelaus_disable_irq(irq);
  	the_menelaus->handlers[irq] = NULL;
  	mutex_unlock(&the_menelaus->lock);
  
  	return ret;
  }
  
  /*
   * Gets scheduled when a card detect interrupt happens. Note that in some cases
   * this line is wired to card cover switch rather than the card detect switch
   * in each slot. In this case the cards are not seen by menelaus.
   * FIXME: Add handling for D1 too
   */
  static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw)
  {
  	int reg;
  	unsigned char card_mask = 0;
  
  	reg = menelaus_read_reg(MENELAUS_MCT_PIN_ST);
  	if (reg < 0)
  		return;
  
  	if (!(reg & 0x1))
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
268
  		card_mask |= MCT_PIN_ST_S1_CD_ST;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
269
270
  
  	if (!(reg & 0x2))
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
271
  		card_mask |= MCT_PIN_ST_S2_CD_ST;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  
  	if (menelaus_hw->mmc_callback)
  		menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
  					  card_mask);
  }
  
  /*
   * Toggles the MMC slots between open-drain and push-pull mode.
   */
  int menelaus_set_mmc_opendrain(int slot, int enable)
  {
  	int ret, val;
  
  	if (slot != 1 && slot != 2)
  		return -EINVAL;
  	mutex_lock(&the_menelaus->lock);
  	ret = menelaus_read_reg(MENELAUS_MCT_CTRL1);
  	if (ret < 0) {
  		mutex_unlock(&the_menelaus->lock);
  		return ret;
  	}
  	val = ret;
  	if (slot == 1) {
  		if (enable)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
296
  			val |= MCT_CTRL1_S1_CMD_OD;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
297
  		else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
298
  			val &= ~MCT_CTRL1_S1_CMD_OD;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
299
300
  	} else {
  		if (enable)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
301
  			val |= MCT_CTRL1_S2_CMD_OD;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
302
  		else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
303
  			val &= ~MCT_CTRL1_S2_CMD_OD;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  	}
  	ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
  	mutex_unlock(&the_menelaus->lock);
  
  	return ret;
  }
  EXPORT_SYMBOL(menelaus_set_mmc_opendrain);
  
  int menelaus_set_slot_sel(int enable)
  {
  	int ret;
  
  	mutex_lock(&the_menelaus->lock);
  	ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
  	if (ret < 0)
  		goto out;
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
320
  	ret |= GPIO2_DIR_INPUT;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
321
  	if (enable)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
322
  		ret |= GPIO_CTRL_SLOTSELEN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
323
  	else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
324
  		ret &= ~GPIO_CTRL_SLOTSELEN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  	ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
  out:
  	mutex_unlock(&the_menelaus->lock);
  	return ret;
  }
  EXPORT_SYMBOL(menelaus_set_slot_sel);
  
  int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
  {
  	int ret, val;
  
  	if (slot != 1 && slot != 2)
  		return -EINVAL;
  	if (power >= 3)
  		return -EINVAL;
  
  	mutex_lock(&the_menelaus->lock);
  
  	ret = menelaus_read_reg(MENELAUS_MCT_CTRL2);
  	if (ret < 0)
  		goto out;
  	val = ret;
  	if (slot == 1) {
  		if (cd_en)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
349
  			val |= MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
350
  		else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
351
  			val &= ~(MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
352
353
  	} else {
  		if (cd_en)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
354
  			val |= MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
355
  		else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
356
  			val &= ~(MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
357
358
359
360
361
362
363
364
365
366
367
  	}
  	ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val);
  	if (ret < 0)
  		goto out;
  
  	ret = menelaus_read_reg(MENELAUS_MCT_CTRL3);
  	if (ret < 0)
  		goto out;
  	val = ret;
  	if (slot == 1) {
  		if (enable)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
368
  			val |= MCT_CTRL3_SLOT1_EN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
369
  		else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
370
  			val &= ~MCT_CTRL3_SLOT1_EN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
371
372
373
374
  	} else {
  		int b;
  
  		if (enable)
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
375
  			val |= MCT_CTRL3_SLOT2_EN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
376
  		else
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
377
  			val &= ~MCT_CTRL3_SLOT2_EN;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
378
  		b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
379
  		b &= ~(MCT_CTRL2_VS2_SEL_D0 | MCT_CTRL2_VS2_SEL_D1);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
380
381
382
383
384
385
  		b |= power;
  		ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
  		if (ret < 0)
  			goto out;
  	}
  	/* Disable autonomous shutdown */
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
386
  	val &= ~(MCT_CTRL3_S1_AUTO_EN | MCT_CTRL3_S2_AUTO_EN);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  	ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
  out:
  	mutex_unlock(&the_menelaus->lock);
  	return ret;
  }
  EXPORT_SYMBOL(menelaus_set_mmc_slot);
  
  int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
  				   void *data)
  {
  	int ret = 0;
  
  	the_menelaus->mmc_callback_data = data;
  	the_menelaus->mmc_callback = callback;
  	ret = menelaus_add_irq_work(MENELAUS_MMC_S1CD_IRQ,
  				    menelaus_mmc_cd_work);
  	if (ret < 0)
  		return ret;
  	ret = menelaus_add_irq_work(MENELAUS_MMC_S2CD_IRQ,
  				    menelaus_mmc_cd_work);
  	if (ret < 0)
  		return ret;
  	ret = menelaus_add_irq_work(MENELAUS_MMC_S1D1_IRQ,
  				    menelaus_mmc_cd_work);
  	if (ret < 0)
  		return ret;
  	ret = menelaus_add_irq_work(MENELAUS_MMC_S2D1_IRQ,
  				    menelaus_mmc_cd_work);
  
  	return ret;
  }
  EXPORT_SYMBOL(menelaus_register_mmc_callback);
  
  void menelaus_unregister_mmc_callback(void)
  {
  	menelaus_remove_irq_work(MENELAUS_MMC_S1CD_IRQ);
  	menelaus_remove_irq_work(MENELAUS_MMC_S2CD_IRQ);
  	menelaus_remove_irq_work(MENELAUS_MMC_S1D1_IRQ);
  	menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ);
  
  	the_menelaus->mmc_callback = NULL;
59a9f7a32   Jingoo Han   mfd: menelaus: Us...
428
  	the_menelaus->mmc_callback_data = NULL;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  }
  EXPORT_SYMBOL(menelaus_unregister_mmc_callback);
  
  struct menelaus_vtg {
  	const char *name;
  	u8 vtg_reg;
  	u8 vtg_shift;
  	u8 vtg_bits;
  	u8 mode_reg;
  };
  
  struct menelaus_vtg_value {
  	u16 vtg;
  	u16 val;
  };
  
  static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV,
  				int vtg_val, int mode)
  {
  	int val, ret;
  	struct i2c_client *c = the_menelaus->client;
  
  	mutex_lock(&the_menelaus->lock);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  
  	ret = menelaus_read_reg(vtg->vtg_reg);
  	if (ret < 0)
  		goto out;
  	val = ret & ~(((1 << vtg->vtg_bits) - 1) << vtg->vtg_shift);
  	val |= vtg_val << vtg->vtg_shift;
  
  	dev_dbg(&c->dev, "Setting voltage '%s'"
  			 "to %d mV (reg 0x%02x, val 0x%02x)
  ",
  			vtg->name, mV, vtg->vtg_reg, val);
  
  	ret = menelaus_write_reg(vtg->vtg_reg, val);
  	if (ret < 0)
  		goto out;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  	ret = menelaus_write_reg(vtg->mode_reg, mode);
  out:
  	mutex_unlock(&the_menelaus->lock);
  	if (ret == 0) {
  		/* Wait for voltage to stabilize */
  		msleep(1);
  	}
  	return ret;
  }
  
  static int menelaus_get_vtg_value(int vtg, const struct menelaus_vtg_value *tbl,
  				  int n)
  {
  	int i;
  
  	for (i = 0; i < n; i++, tbl++)
  		if (tbl->vtg == vtg)
  			return tbl->val;
  	return -EINVAL;
  }
  
  /*
   * Vcore can be programmed in two ways:
   * SW-controlled: Required voltage is programmed into VCORE_CTRL1
   * HW-controlled: Required range (roof-floor) is programmed into VCORE_CTRL3
   * and VCORE_CTRL4
   *
   * Call correct 'set' function accordingly
   */
  
  static const struct menelaus_vtg_value vcore_values[] = {
  	{ 1000, 0 },
  	{ 1025, 1 },
  	{ 1050, 2 },
  	{ 1075, 3 },
  	{ 1100, 4 },
  	{ 1125, 5 },
  	{ 1150, 6 },
  	{ 1175, 7 },
  	{ 1200, 8 },
  	{ 1225, 9 },
  	{ 1250, 10 },
  	{ 1275, 11 },
  	{ 1300, 12 },
  	{ 1325, 13 },
  	{ 1350, 14 },
  	{ 1375, 15 },
  	{ 1400, 16 },
  	{ 1425, 17 },
  	{ 1450, 18 },
  };
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV)
  {
  	int fval, rval, val, ret;
  	struct i2c_client *c = the_menelaus->client;
  
  	rval = menelaus_get_vtg_value(roof_mV, vcore_values,
  				      ARRAY_SIZE(vcore_values));
  	if (rval < 0)
  		return -EINVAL;
  	fval = menelaus_get_vtg_value(floor_mV, vcore_values,
  				      ARRAY_SIZE(vcore_values));
  	if (fval < 0)
  		return -EINVAL;
  
  	dev_dbg(&c->dev, "Setting VCORE FLOOR to %d mV and ROOF to %d mV
  ",
  	       floor_mV, roof_mV);
  
  	mutex_lock(&the_menelaus->lock);
  	ret = menelaus_write_reg(MENELAUS_VCORE_CTRL3, fval);
  	if (ret < 0)
  		goto out;
  	ret = menelaus_write_reg(MENELAUS_VCORE_CTRL4, rval);
  	if (ret < 0)
  		goto out;
  	if (!the_menelaus->vcore_hw_mode) {
  		val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
  		/* HW mode, turn OFF byte comparator */
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
546
  		val |= (VCORE_CTRL1_HW_NSW | VCORE_CTRL1_BYP_COMP);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  		ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
  		the_menelaus->vcore_hw_mode = 1;
  	}
  	msleep(1);
  out:
  	mutex_unlock(&the_menelaus->lock);
  	return ret;
  }
  
  static const struct menelaus_vtg vmem_vtg = {
  	.name = "VMEM",
  	.vtg_reg = MENELAUS_LDO_CTRL1,
  	.vtg_shift = 0,
  	.vtg_bits = 2,
  	.mode_reg = MENELAUS_LDO_CTRL3,
  };
  
  static const struct menelaus_vtg_value vmem_values[] = {
  	{ 1500, 0 },
  	{ 1800, 1 },
  	{ 1900, 2 },
  	{ 2500, 3 },
  };
  
  int menelaus_set_vmem(unsigned int mV)
  {
  	int val;
  
  	if (mV == 0)
  		return menelaus_set_voltage(&vmem_vtg, 0, 0, 0);
  
  	val = menelaus_get_vtg_value(mV, vmem_values, ARRAY_SIZE(vmem_values));
  	if (val < 0)
  		return -EINVAL;
  	return menelaus_set_voltage(&vmem_vtg, mV, val, 0x02);
  }
  EXPORT_SYMBOL(menelaus_set_vmem);
  
  static const struct menelaus_vtg vio_vtg = {
  	.name = "VIO",
  	.vtg_reg = MENELAUS_LDO_CTRL1,
  	.vtg_shift = 2,
  	.vtg_bits = 2,
  	.mode_reg = MENELAUS_LDO_CTRL4,
  };
  
  static const struct menelaus_vtg_value vio_values[] = {
  	{ 1500, 0 },
  	{ 1800, 1 },
  	{ 2500, 2 },
  	{ 2800, 3 },
  };
  
  int menelaus_set_vio(unsigned int mV)
  {
  	int val;
  
  	if (mV == 0)
  		return menelaus_set_voltage(&vio_vtg, 0, 0, 0);
  
  	val = menelaus_get_vtg_value(mV, vio_values, ARRAY_SIZE(vio_values));
  	if (val < 0)
  		return -EINVAL;
  	return menelaus_set_voltage(&vio_vtg, mV, val, 0x02);
  }
  EXPORT_SYMBOL(menelaus_set_vio);
  
  static const struct menelaus_vtg_value vdcdc_values[] = {
  	{ 1500, 0 },
  	{ 1800, 1 },
  	{ 2000, 2 },
  	{ 2200, 3 },
  	{ 2400, 4 },
  	{ 2800, 5 },
  	{ 3000, 6 },
  	{ 3300, 7 },
  };
  
  static const struct menelaus_vtg vdcdc2_vtg = {
  	.name = "VDCDC2",
  	.vtg_reg = MENELAUS_DCDC_CTRL1,
  	.vtg_shift = 0,
  	.vtg_bits = 3,
  	.mode_reg = MENELAUS_DCDC_CTRL2,
  };
  
  static const struct menelaus_vtg vdcdc3_vtg = {
  	.name = "VDCDC3",
  	.vtg_reg = MENELAUS_DCDC_CTRL1,
  	.vtg_shift = 3,
  	.vtg_bits = 3,
  	.mode_reg = MENELAUS_DCDC_CTRL3,
  };
  
  int menelaus_set_vdcdc(int dcdc, unsigned int mV)
  {
  	const struct menelaus_vtg *vtg;
  	int val;
  
  	if (dcdc != 2 && dcdc != 3)
  		return -EINVAL;
  	if (dcdc == 2)
  		vtg = &vdcdc2_vtg;
  	else
  		vtg = &vdcdc3_vtg;
  
  	if (mV == 0)
  		return menelaus_set_voltage(vtg, 0, 0, 0);
  
  	val = menelaus_get_vtg_value(mV, vdcdc_values,
  				     ARRAY_SIZE(vdcdc_values));
  	if (val < 0)
  		return -EINVAL;
  	return menelaus_set_voltage(vtg, mV, val, 0x03);
  }
  
  static const struct menelaus_vtg_value vmmc_values[] = {
  	{ 1850, 0 },
  	{ 2800, 1 },
  	{ 3000, 2 },
  	{ 3100, 3 },
  };
  
  static const struct menelaus_vtg vmmc_vtg = {
  	.name = "VMMC",
  	.vtg_reg = MENELAUS_LDO_CTRL1,
  	.vtg_shift = 6,
  	.vtg_bits = 2,
  	.mode_reg = MENELAUS_LDO_CTRL7,
  };
  
  int menelaus_set_vmmc(unsigned int mV)
  {
  	int val;
  
  	if (mV == 0)
  		return menelaus_set_voltage(&vmmc_vtg, 0, 0, 0);
  
  	val = menelaus_get_vtg_value(mV, vmmc_values, ARRAY_SIZE(vmmc_values));
  	if (val < 0)
  		return -EINVAL;
  	return menelaus_set_voltage(&vmmc_vtg, mV, val, 0x02);
  }
  EXPORT_SYMBOL(menelaus_set_vmmc);
  
  
  static const struct menelaus_vtg_value vaux_values[] = {
  	{ 1500, 0 },
  	{ 1800, 1 },
  	{ 2500, 2 },
  	{ 2800, 3 },
  };
  
  static const struct menelaus_vtg vaux_vtg = {
  	.name = "VAUX",
  	.vtg_reg = MENELAUS_LDO_CTRL1,
  	.vtg_shift = 4,
  	.vtg_bits = 2,
  	.mode_reg = MENELAUS_LDO_CTRL6,
  };
  
  int menelaus_set_vaux(unsigned int mV)
  {
  	int val;
  
  	if (mV == 0)
  		return menelaus_set_voltage(&vaux_vtg, 0, 0, 0);
  
  	val = menelaus_get_vtg_value(mV, vaux_values, ARRAY_SIZE(vaux_values));
  	if (val < 0)
  		return -EINVAL;
  	return menelaus_set_voltage(&vaux_vtg, mV, val, 0x02);
  }
  EXPORT_SYMBOL(menelaus_set_vaux);
  
  int menelaus_get_slot_pin_states(void)
  {
  	return menelaus_read_reg(MENELAUS_MCT_PIN_ST);
  }
  EXPORT_SYMBOL(menelaus_get_slot_pin_states);
  
  int menelaus_set_regulator_sleep(int enable, u32 val)
  {
  	int t, ret;
  	struct i2c_client *c = the_menelaus->client;
  
  	mutex_lock(&the_menelaus->lock);
  	ret = menelaus_write_reg(MENELAUS_SLEEP_CTRL2, val);
  	if (ret < 0)
  		goto out;
  
  	dev_dbg(&c->dev, "regulator sleep configuration: %02x
  ", val);
  
  	ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
  	if (ret < 0)
  		goto out;
1c888e2e3   Jarkko Nikula   mfd: Use macros i...
744
  	t = (GPIO_CTRL_SLPCTLEN | GPIO3_DIR_INPUT);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  	if (enable)
  		ret |= t;
  	else
  		ret &= ~t;
  	ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
  out:
  	mutex_unlock(&the_menelaus->lock);
  	return ret;
  }
  
  /*-----------------------------------------------------------------------*/
  
  /* Handles Menelaus interrupts. Does not run in interrupt context */
  static void menelaus_work(struct work_struct *_menelaus)
  {
  	struct menelaus_chip *menelaus =
  			container_of(_menelaus, struct menelaus_chip, work);
  	void (*handler)(struct menelaus_chip *menelaus);
  
  	while (1) {
  		unsigned isr;
  
  		isr = (menelaus_read_reg(MENELAUS_INT_STATUS2)
  				& ~menelaus->mask2) << 8;
  		isr |= menelaus_read_reg(MENELAUS_INT_STATUS1)
  				& ~menelaus->mask1;
  		if (!isr)
  			break;
  
  		while (isr) {
  			int irq = fls(isr) - 1;
  			isr &= ~(1 << irq);
  
  			mutex_lock(&menelaus->lock);
  			menelaus_disable_irq(irq);
  			menelaus_ack_irq(irq);
  			handler = menelaus->handlers[irq];
  			if (handler)
  				handler(menelaus);
  			menelaus_enable_irq(irq);
  			mutex_unlock(&menelaus->lock);
  		}
  	}
  	enable_irq(menelaus->client->irq);
  }
  
  /*
   * We cannot use I2C in interrupt context, so we just schedule work.
   */
  static irqreturn_t menelaus_irq(int irq, void *_menelaus)
  {
  	struct menelaus_chip *menelaus = _menelaus;
  
  	disable_irq_nosync(irq);
  	(void)schedule_work(&menelaus->work);
  
  	return IRQ_HANDLED;
  }
  
  /*-----------------------------------------------------------------------*/
  
  /*
   * The RTC needs to be set once, then it runs on backup battery power.
   * It supports alarms, including system wake alarms (from some modes);
   * and 1/second IRQs if requested.
   */
  #ifdef CONFIG_RTC_DRV_TWL92330
  
  #define RTC_CTRL_RTC_EN		(1 << 0)
  #define RTC_CTRL_AL_EN		(1 << 1)
  #define RTC_CTRL_MODE12		(1 << 2)
  #define RTC_CTRL_EVERY_MASK	(3 << 3)
  #define RTC_CTRL_EVERY_SEC	(0 << 3)
  #define RTC_CTRL_EVERY_MIN	(1 << 3)
  #define RTC_CTRL_EVERY_HR	(2 << 3)
  #define RTC_CTRL_EVERY_DAY	(3 << 3)
  
  #define RTC_UPDATE_EVERY	0x08
  
  #define RTC_HR_PM		(1 << 7)
  
  static void menelaus_to_time(char *regs, struct rtc_time *t)
  {
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
828
829
  	t->tm_sec = bcd2bin(regs[0]);
  	t->tm_min = bcd2bin(regs[1]);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
830
  	if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
831
  		t->tm_hour = bcd2bin(regs[2] & 0x1f) - 1;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
832
833
834
  		if (regs[2] & RTC_HR_PM)
  			t->tm_hour += 12;
  	} else
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
835
836
837
838
  		t->tm_hour = bcd2bin(regs[2] & 0x3f);
  	t->tm_mday = bcd2bin(regs[3]);
  	t->tm_mon = bcd2bin(regs[4]) - 1;
  	t->tm_year = bcd2bin(regs[5]) + 100;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
839
840
841
842
843
  }
  
  static int time_to_menelaus(struct rtc_time *t, int regnum)
  {
  	int	hour, status;
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
844
  	status = menelaus_write_reg(regnum++, bin2bcd(t->tm_sec));
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
845
846
  	if (status < 0)
  		goto fail;
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
847
  	status = menelaus_write_reg(regnum++, bin2bcd(t->tm_min));
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
848
849
850
851
852
853
  	if (status < 0)
  		goto fail;
  
  	if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
  		hour = t->tm_hour + 1;
  		if (hour > 12)
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
854
  			hour = RTC_HR_PM | bin2bcd(hour - 12);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
855
  		else
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
856
  			hour = bin2bcd(hour);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
857
  	} else
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
858
  		hour = bin2bcd(t->tm_hour);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
859
860
861
  	status = menelaus_write_reg(regnum++, hour);
  	if (status < 0)
  		goto fail;
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
862
  	status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mday));
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
863
864
  	if (status < 0)
  		goto fail;
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
865
  	status = menelaus_write_reg(regnum++, bin2bcd(t->tm_mon + 1));
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
866
867
  	if (status < 0)
  		goto fail;
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
868
  	status = menelaus_write_reg(regnum++, bin2bcd(t->tm_year - 100));
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
  	if (status < 0)
  		goto fail;
  
  	return 0;
  fail:
  	dev_err(&the_menelaus->client->dev, "rtc write reg %02x, err %d
  ",
  			--regnum, status);
  	return status;
  }
  
  static int menelaus_read_time(struct device *dev, struct rtc_time *t)
  {
  	struct i2c_msg	msg[2];
  	char		regs[7];
  	int		status;
  
  	/* block read date and time registers */
  	regs[0] = MENELAUS_RTC_SEC;
  
  	msg[0].addr = MENELAUS_I2C_ADDRESS;
  	msg[0].flags = 0;
  	msg[0].len = 1;
  	msg[0].buf = regs;
  
  	msg[1].addr = MENELAUS_I2C_ADDRESS;
  	msg[1].flags = I2C_M_RD;
  	msg[1].len = sizeof(regs);
  	msg[1].buf = regs;
  
  	status = i2c_transfer(the_menelaus->client->adapter, msg, 2);
  	if (status != 2) {
  		dev_err(dev, "%s error %d
  ", "read", status);
  		return -EIO;
  	}
  
  	menelaus_to_time(regs, t);
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
907
  	t->tm_wday = bcd2bin(regs[6]);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
908
909
910
911
912
913
914
915
916
917
918
919
  
  	return 0;
  }
  
  static int menelaus_set_time(struct device *dev, struct rtc_time *t)
  {
  	int		status;
  
  	/* write date and time registers */
  	status = time_to_menelaus(t, MENELAUS_RTC_SEC);
  	if (status < 0)
  		return status;
e4d33969c   Adrian Bunk   i2c: use bcd2bin/...
920
  	status = menelaus_write_reg(MENELAUS_RTC_WKDAY, bin2bcd(t->tm_wday));
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
921
  	if (status < 0) {
c1147cc6d   David Brownell   i2c/menelaus: Bui...
922
  		dev_err(&the_menelaus->client->dev, "rtc write reg %02x "
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  				"err %d
  ", MENELAUS_RTC_WKDAY, status);
  		return status;
  	}
  
  	/* now commit the write */
  	status = menelaus_write_reg(MENELAUS_RTC_UPDATE, RTC_UPDATE_EVERY);
  	if (status < 0)
  		dev_err(&the_menelaus->client->dev, "rtc commit time, err %d
  ",
  				status);
  
  	return 0;
  }
  
  static int menelaus_read_alarm(struct device *dev, struct rtc_wkalrm *w)
  {
  	struct i2c_msg	msg[2];
  	char		regs[6];
  	int		status;
  
  	/* block read alarm registers */
  	regs[0] = MENELAUS_RTC_AL_SEC;
  
  	msg[0].addr = MENELAUS_I2C_ADDRESS;
  	msg[0].flags = 0;
  	msg[0].len = 1;
  	msg[0].buf = regs;
  
  	msg[1].addr = MENELAUS_I2C_ADDRESS;
  	msg[1].flags = I2C_M_RD;
  	msg[1].len = sizeof(regs);
  	msg[1].buf = regs;
  
  	status = i2c_transfer(the_menelaus->client->adapter, msg, 2);
  	if (status != 2) {
  		dev_err(dev, "%s error %d
  ", "alarm read", status);
  		return -EIO;
  	}
  
  	menelaus_to_time(regs, &w->time);
  
  	w->enabled = !!(the_menelaus->rtc_control & RTC_CTRL_AL_EN);
  
  	/* NOTE we *could* check if actually pending... */
  	w->pending = 0;
  
  	return 0;
  }
  
  static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w)
  {
  	int		status;
  
  	if (the_menelaus->client->irq <= 0 && w->enabled)
  		return -ENODEV;
  
  	/* clear previous alarm enable */
  	if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) {
  		the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
  		status = menelaus_write_reg(MENELAUS_RTC_CTRL,
  				the_menelaus->rtc_control);
  		if (status < 0)
  			return status;
  	}
  
  	/* write alarm registers */
  	status = time_to_menelaus(&w->time, MENELAUS_RTC_AL_SEC);
  	if (status < 0)
  		return status;
  
  	/* enable alarm if requested */
  	if (w->enabled) {
  		the_menelaus->rtc_control |= RTC_CTRL_AL_EN;
  		status = menelaus_write_reg(MENELAUS_RTC_CTRL,
  				the_menelaus->rtc_control);
  	}
  
  	return status;
  }
  
  #ifdef CONFIG_RTC_INTF_DEV
  
  static void menelaus_rtc_update_work(struct menelaus_chip *m)
  {
  	/* report 1/sec update */
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1010
  	rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  }
  
  static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
  {
  	int	status;
  
  	if (the_menelaus->client->irq <= 0)
  		return -ENOIOCTLCMD;
  
  	switch (cmd) {
  	/* alarm IRQ */
  	case RTC_AIE_ON:
  		if (the_menelaus->rtc_control & RTC_CTRL_AL_EN)
  			return 0;
  		the_menelaus->rtc_control |= RTC_CTRL_AL_EN;
  		break;
  	case RTC_AIE_OFF:
  		if (!(the_menelaus->rtc_control & RTC_CTRL_AL_EN))
  			return 0;
  		the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
  		break;
  	/* 1/second "update" IRQ */
  	case RTC_UIE_ON:
  		if (the_menelaus->uie)
  			return 0;
  		status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ);
  		status = menelaus_add_irq_work(MENELAUS_RTCTMR_IRQ,
  				menelaus_rtc_update_work);
  		if (status == 0)
  			the_menelaus->uie = 1;
  		return status;
  	case RTC_UIE_OFF:
  		if (!the_menelaus->uie)
  			return 0;
  		status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ);
  		if (status == 0)
  			the_menelaus->uie = 0;
  		return status;
  	default:
  		return -ENOIOCTLCMD;
  	}
  	return menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control);
  }
  
  #else
  #define menelaus_ioctl	NULL
  #endif
  
  /* REVISIT no compensation register support ... */
  
  static const struct rtc_class_ops menelaus_rtc_ops = {
  	.ioctl			= menelaus_ioctl,
  	.read_time		= menelaus_read_time,
  	.set_time		= menelaus_set_time,
  	.read_alarm		= menelaus_read_alarm,
  	.set_alarm		= menelaus_set_alarm,
  };
  
  static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
  {
  	/* report alarm */
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1072
  	rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1073
1074
1075
1076
1077
1078
1079
1080
1081
  
  	/* then disable it; alarms are oneshot */
  	the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
  	menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control);
  }
  
  static inline void menelaus_rtc_init(struct menelaus_chip *m)
  {
  	int	alarm = (m->client->irq > 0);
9612f8f50   Alexandre Belloni   mfd: menelaus: Fi...
1082
  	int	err;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1083
1084
1085
1086
1087
1088
1089
  
  	/* assume 32KDETEN pin is pulled high */
  	if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) {
  		dev_dbg(&m->client->dev, "no 32k oscillator
  ");
  		return;
  	}
9612f8f50   Alexandre Belloni   mfd: menelaus: Fi...
1090
1091
1092
1093
1094
  	m->rtc = devm_rtc_allocate_device(&m->client->dev);
  	if (IS_ERR(m->rtc))
  		return;
  
  	m->rtc->ops = &menelaus_rtc_ops;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  	/* support RTC alarm; it can issue wakeups */
  	if (alarm) {
  		if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ,
  				menelaus_rtc_alarm_work) < 0) {
  			dev_err(&m->client->dev, "can't handle RTC alarm
  ");
  			return;
  		}
  		device_init_wakeup(&m->client->dev, 1);
  	}
  
  	/* be sure RTC is enabled; allow 1/sec irqs; leave 12hr mode alone */
  	m->rtc_control = menelaus_read_reg(MENELAUS_RTC_CTRL);
  	if (!(m->rtc_control & RTC_CTRL_RTC_EN)
  			|| (m->rtc_control & RTC_CTRL_AL_EN)
  			|| (m->rtc_control & RTC_CTRL_EVERY_MASK)) {
  		if (!(m->rtc_control & RTC_CTRL_RTC_EN)) {
  			dev_warn(&m->client->dev, "rtc clock needs setting
  ");
  			m->rtc_control |= RTC_CTRL_RTC_EN;
  		}
  		m->rtc_control &= ~RTC_CTRL_EVERY_MASK;
  		m->rtc_control &= ~RTC_CTRL_AL_EN;
  		menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control);
  	}
9612f8f50   Alexandre Belloni   mfd: menelaus: Fi...
1120
1121
  	err = rtc_register_device(m->rtc);
  	if (err) {
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1122
1123
1124
1125
  		if (alarm) {
  			menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ);
  			device_init_wakeup(&m->client->dev, 0);
  		}
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
  		the_menelaus->rtc = NULL;
  	}
  }
  
  #else
  
  static inline void menelaus_rtc_init(struct menelaus_chip *m)
  {
  	/* nothing */
  }
  
  #endif
  
  /*-----------------------------------------------------------------------*/
  
  static struct i2c_driver menelaus_i2c_driver;
d2653e927   Jean Delvare   i2c: Add support ...
1142
1143
  static int menelaus_probe(struct i2c_client *client,
  			  const struct i2c_device_id *id)
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1144
1145
  {
  	struct menelaus_chip	*menelaus;
42a71ef97   Julia Lawall   mfd: menelaus: Fi...
1146
  	int			rev = 0;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1147
1148
  	int			err = 0;
  	struct menelaus_platform_data *menelaus_pdata =
334a41ce9   Jingoo Han   mfd: Use dev_get_...
1149
  					dev_get_platdata(&client->dev);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1150
1151
1152
1153
1154
1155
1156
  
  	if (the_menelaus) {
  		dev_dbg(&client->dev, "only one %s for now
  ",
  				DRIVER_NAME);
  		return -ENODEV;
  	}
7a4043112   Jingoo Han   mfd: menelaus: Us...
1157
  	menelaus = devm_kzalloc(&client->dev, sizeof(*menelaus), GFP_KERNEL);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  	if (!menelaus)
  		return -ENOMEM;
  
  	i2c_set_clientdata(client, menelaus);
  
  	the_menelaus = menelaus;
  	menelaus->client = client;
  
  	/* If a true probe check the device */
  	rev = menelaus_read_reg(MENELAUS_REV);
  	if (rev < 0) {
1f7c8234c   Emil Medve   Make the pr_*() f...
1169
  		pr_err(DRIVER_NAME ": device not found");
7a4043112   Jingoo Han   mfd: menelaus: Us...
1170
  		return -ENODEV;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  	}
  
  	/* Ack and disable all Menelaus interrupts */
  	menelaus_write_reg(MENELAUS_INT_ACK1, 0xff);
  	menelaus_write_reg(MENELAUS_INT_ACK2, 0xff);
  	menelaus_write_reg(MENELAUS_INT_MASK1, 0xff);
  	menelaus_write_reg(MENELAUS_INT_MASK2, 0xff);
  	menelaus->mask1 = 0xff;
  	menelaus->mask2 = 0xff;
  
  	/* Set output buffer strengths */
  	menelaus_write_reg(MENELAUS_MCT_CTRL1, 0x73);
  
  	if (client->irq > 0) {
f742b96e4   Yong Zhang   mfd: Remove IRQF_...
1185
  		err = request_irq(client->irq, menelaus_irq, 0,
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1186
1187
  				  DRIVER_NAME, menelaus);
  		if (err) {
898eb71cb   Joe Perches   Add missing newli...
1188
1189
  			dev_dbg(&client->dev,  "can't get IRQ %d, err %d
  ",
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1190
  					client->irq, err);
7a4043112   Jingoo Han   mfd: menelaus: Us...
1191
  			return err;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1192
1193
1194
1195
1196
1197
1198
1199
  		}
  	}
  
  	mutex_init(&menelaus->lock);
  	INIT_WORK(&menelaus->work, menelaus_work);
  
  	pr_info("Menelaus rev %d.%d
  ", rev >> 4, rev & 0x0f);
42a71ef97   Julia Lawall   mfd: menelaus: Fi...
1200
1201
  	err = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
  	if (err < 0)
7a4043112   Jingoo Han   mfd: menelaus: Us...
1202
  		goto fail;
dfe514b67   Aaro Koskinen   mfd: menelaus: Us...
1203
  	if (err & VCORE_CTRL1_HW_NSW)
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1204
1205
1206
1207
1208
1209
1210
  		menelaus->vcore_hw_mode = 1;
  	else
  		menelaus->vcore_hw_mode = 0;
  
  	if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) {
  		err = menelaus_pdata->late_init(&client->dev);
  		if (err < 0)
7a4043112   Jingoo Han   mfd: menelaus: Us...
1211
  			goto fail;
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1212
1213
1214
1215
1216
  	}
  
  	menelaus_rtc_init(menelaus);
  
  	return 0;
7a4043112   Jingoo Han   mfd: menelaus: Us...
1217
  fail:
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1218
  	free_irq(client->irq, menelaus);
43829731d   Tejun Heo   workqueue: deprec...
1219
  	flush_work(&menelaus->work);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1220
1221
  	return err;
  }
eac8a5c91   Dmitry Torokhov   mfd: menelaus: Re...
1222
  static int menelaus_remove(struct i2c_client *client)
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1223
1224
1225
1226
  {
  	struct menelaus_chip	*menelaus = i2c_get_clientdata(client);
  
  	free_irq(client->irq, menelaus);
43829731d   Tejun Heo   workqueue: deprec...
1227
  	flush_work(&menelaus->work);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1228
1229
1230
  	the_menelaus = NULL;
  	return 0;
  }
3760f7367   Jean Delvare   i2c: Convert most...
1231
1232
1233
1234
1235
  static const struct i2c_device_id menelaus_id[] = {
  	{ "menelaus", 0 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, menelaus_id);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1236
1237
1238
1239
1240
  static struct i2c_driver menelaus_i2c_driver = {
  	.driver = {
  		.name		= DRIVER_NAME,
  	},
  	.probe		= menelaus_probe,
eac8a5c91   Dmitry Torokhov   mfd: menelaus: Re...
1241
  	.remove		= menelaus_remove,
3760f7367   Jean Delvare   i2c: Convert most...
1242
  	.id_table	= menelaus_id,
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1243
  };
1d3c7f566   Sachin Kamat   mfd: menelaus: Us...
1244
  module_i2c_driver(menelaus_i2c_driver);
0c4a59fed   Tony Lindgren   OMAP: add TI TWL9...
1245
1246
1247
1248
  
  MODULE_AUTHOR("Texas Instruments, Inc. (and others)");
  MODULE_DESCRIPTION("I2C interface for Menelaus.");
  MODULE_LICENSE("GPL");