blob: 78dc7505b965ad80da0e25f334266b4296100f14 [file] [log] [blame]
Chanwoo Choidb1b9032012-07-17 13:28:28 +09001/*
2 * extcon-max77693.c - MAX77693 extcon driver to support MAX77693 MUIC
3 *
4 * Copyright (C) 2012 Samsung Electrnoics
5 * Chanwoo Choi <cw00.choi@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/i2c.h>
21#include <linux/slab.h>
22#include <linux/interrupt.h>
23#include <linux/err.h>
24#include <linux/platform_device.h>
25#include <linux/mfd/max77693.h>
26#include <linux/mfd/max77693-private.h>
27#include <linux/extcon.h>
28#include <linux/regmap.h>
29#include <linux/irqdomain.h>
30
31#define DEV_NAME "max77693-muic"
32
Chanwoo Choidb1b9032012-07-17 13:28:28 +090033enum max77693_muic_adc_debounce_time {
34 ADC_DEBOUNCE_TIME_5MS = 0,
35 ADC_DEBOUNCE_TIME_10MS,
36 ADC_DEBOUNCE_TIME_25MS,
37 ADC_DEBOUNCE_TIME_38_62MS,
38};
39
40struct max77693_muic_info {
41 struct device *dev;
42 struct max77693_dev *max77693;
43 struct extcon_dev *edev;
Chanwoo Choi154f757f2012-11-27 09:40:32 +090044 int prev_cable_type;
45 int prev_cable_type_gnd;
Chanwoo Choidb1b9032012-07-17 13:28:28 +090046 int prev_chg_type;
47 u8 status[2];
48
49 int irq;
50 struct work_struct irq_work;
51 struct mutex mutex;
52};
53
Chanwoo Choi154f757f2012-11-27 09:40:32 +090054enum max77693_muic_cable_group {
55 MAX77693_CABLE_GROUP_ADC = 0,
56 MAX77693_CABLE_GROUP_ADC_GND,
57 MAX77693_CABLE_GROUP_CHG,
58 MAX77693_CABLE_GROUP_VBVOLT,
59};
60
Chanwoo Choidb1b9032012-07-17 13:28:28 +090061enum max77693_muic_charger_type {
62 MAX77693_CHARGER_TYPE_NONE = 0,
63 MAX77693_CHARGER_TYPE_USB,
64 MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT,
65 MAX77693_CHARGER_TYPE_DEDICATED_CHG,
66 MAX77693_CHARGER_TYPE_APPLE_500MA,
67 MAX77693_CHARGER_TYPE_APPLE_1A_2A,
68 MAX77693_CHARGER_TYPE_DEAD_BATTERY = 7,
69};
70
71/**
72 * struct max77693_muic_irq
73 * @irq: the index of irq list of MUIC device.
74 * @name: the name of irq.
75 * @virq: the virtual irq to use irq domain
76 */
77struct max77693_muic_irq {
78 unsigned int irq;
79 const char *name;
80 unsigned int virq;
81};
82
83static struct max77693_muic_irq muic_irqs[] = {
84 { MAX77693_MUIC_IRQ_INT1_ADC, "muic-ADC" },
85 { MAX77693_MUIC_IRQ_INT1_ADC_LOW, "muic-ADCLOW" },
86 { MAX77693_MUIC_IRQ_INT1_ADC_ERR, "muic-ADCError" },
87 { MAX77693_MUIC_IRQ_INT1_ADC1K, "muic-ADC1K" },
88 { MAX77693_MUIC_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
89 { MAX77693_MUIC_IRQ_INT2_CHGDETREUN, "muic-CHGDETREUN" },
90 { MAX77693_MUIC_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
91 { MAX77693_MUIC_IRQ_INT2_DXOVP, "muic-DXOVP" },
92 { MAX77693_MUIC_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
93 { MAX77693_MUIC_IRQ_INT2_VIDRM, "muic-VIDRM" },
94 { MAX77693_MUIC_IRQ_INT3_EOC, "muic-EOC" },
95 { MAX77693_MUIC_IRQ_INT3_CGMBC, "muic-CGMBC" },
96 { MAX77693_MUIC_IRQ_INT3_OVP, "muic-OVP" },
97 { MAX77693_MUIC_IRQ_INT3_MBCCHG_ERR, "muic-MBCCHG_ERR" },
98 { MAX77693_MUIC_IRQ_INT3_CHG_ENABLED, "muic-CHG_ENABLED" },
99 { MAX77693_MUIC_IRQ_INT3_BAT_DET, "muic-BAT_DET" },
100};
101
102/* Define supported accessory type */
103enum max77693_muic_acc_type {
104 MAX77693_MUIC_ADC_GROUND = 0x0,
105 MAX77693_MUIC_ADC_SEND_END_BUTTON,
106 MAX77693_MUIC_ADC_REMOTE_S1_BUTTON,
107 MAX77693_MUIC_ADC_REMOTE_S2_BUTTON,
108 MAX77693_MUIC_ADC_REMOTE_S3_BUTTON,
109 MAX77693_MUIC_ADC_REMOTE_S4_BUTTON,
110 MAX77693_MUIC_ADC_REMOTE_S5_BUTTON,
111 MAX77693_MUIC_ADC_REMOTE_S6_BUTTON,
112 MAX77693_MUIC_ADC_REMOTE_S7_BUTTON,
113 MAX77693_MUIC_ADC_REMOTE_S8_BUTTON,
114 MAX77693_MUIC_ADC_REMOTE_S9_BUTTON,
115 MAX77693_MUIC_ADC_REMOTE_S10_BUTTON,
116 MAX77693_MUIC_ADC_REMOTE_S11_BUTTON,
117 MAX77693_MUIC_ADC_REMOTE_S12_BUTTON,
118 MAX77693_MUIC_ADC_RESERVED_ACC_1,
119 MAX77693_MUIC_ADC_RESERVED_ACC_2,
120 MAX77693_MUIC_ADC_RESERVED_ACC_3,
121 MAX77693_MUIC_ADC_RESERVED_ACC_4,
122 MAX77693_MUIC_ADC_RESERVED_ACC_5,
123 MAX77693_MUIC_ADC_CEA936_AUDIO,
124 MAX77693_MUIC_ADC_PHONE_POWERED_DEV,
125 MAX77693_MUIC_ADC_TTY_CONVERTER,
126 MAX77693_MUIC_ADC_UART_CABLE,
127 MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG,
128 MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF,
129 MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON,
130 MAX77693_MUIC_ADC_AV_CABLE_NOLOAD,
131 MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG,
132 MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF,
133 MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON,
134 MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE,
135 MAX77693_MUIC_ADC_OPEN,
136
137 /* The below accessories have same ADC value so ADCLow and
138 ADC1K bit is used to separate specific accessory */
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900139 MAX77693_MUIC_GND_USB_OTG = 0x100, /* ADC:0x0, VBVolot:0, ADCLow:0, ADC1K:0 */
140 MAX77693_MUIC_GND_USB_OTG_VB = 0x104, /* ADC:0x0, VBVolot:1, ADCLow:0, ADC1K:0 */
141 MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:0 */
142 MAX77693_MUIC_GND_MHL = 0x103, /* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:1 */
143 MAX77693_MUIC_GND_MHL_VB = 0x107, /* ADC:0x0, VBVolot:1, ADCLow:1, ADC1K:1 */
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900144};
145
146/* MAX77693 MUIC device support below list of accessories(external connector) */
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900147enum {
148 EXTCON_CABLE_USB = 0,
149 EXTCON_CABLE_USB_HOST,
150 EXTCON_CABLE_TA,
151 EXTCON_CABLE_FAST_CHARGER,
152 EXTCON_CABLE_SLOW_CHARGER,
153 EXTCON_CABLE_CHARGE_DOWNSTREAM,
154 EXTCON_CABLE_MHL,
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900155 EXTCON_CABLE_MHL_TA,
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900156 EXTCON_CABLE_AUDIO_VIDEO_LOAD,
157 EXTCON_CABLE_AUDIO_VIDEO_NOLOAD,
158 EXTCON_CABLE_JIG,
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900159
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900160 _EXTCON_CABLE_NUM,
161};
162
163const char *max77693_extcon_cable[] = {
164 [EXTCON_CABLE_USB] = "USB",
165 [EXTCON_CABLE_USB_HOST] = "USB-Host",
166 [EXTCON_CABLE_TA] = "TA",
167 [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
168 [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
169 [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
170 [EXTCON_CABLE_MHL] = "MHL",
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900171 [EXTCON_CABLE_MHL_TA] = "MHL_TA",
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900172 [EXTCON_CABLE_AUDIO_VIDEO_LOAD] = "Audio-video-load",
173 [EXTCON_CABLE_AUDIO_VIDEO_NOLOAD] = "Audio-video-noload",
174 [EXTCON_CABLE_JIG] = "JIG",
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900175 NULL,
176};
177
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900178/*
179 * max77693_muic_set_debounce_time - Set the debounce time of ADC
180 * @info: the instance including private data of max77693 MUIC
181 * @time: the debounce time of ADC
182 */
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900183static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
184 enum max77693_muic_adc_debounce_time time)
185{
Axel Linbf2627d2012-10-04 09:55:23 +0900186 int ret;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900187
188 switch (time) {
189 case ADC_DEBOUNCE_TIME_5MS:
190 case ADC_DEBOUNCE_TIME_10MS:
191 case ADC_DEBOUNCE_TIME_25MS:
192 case ADC_DEBOUNCE_TIME_38_62MS:
Axel Linbf2627d2012-10-04 09:55:23 +0900193 ret = max77693_update_reg(info->max77693->regmap_muic,
194 MAX77693_MUIC_REG_CTRL3,
195 time << CONTROL3_ADCDBSET_SHIFT,
196 CONTROL3_ADCDBSET_MASK);
197 if (ret)
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900198 dev_err(info->dev, "failed to set ADC debounce time\n");
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900199 break;
200 default:
201 dev_err(info->dev, "invalid ADC debounce time\n");
202 ret = -EINVAL;
203 break;
204 }
205
206 return ret;
207};
208
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900209/*
210 * max77693_muic_set_path - Set hardware line according to attached cable
211 * @info: the instance including private data of max77693 MUIC
212 * @value: the path according to attached cable
213 * @attached: the state of cable (true:attached, false:detached)
214 *
215 * The max77693 MUIC device share outside H/W line among a varity of cables
216 * so, this function set internal path of H/W line according to the type of
217 * attached cable.
218 */
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900219static int max77693_muic_set_path(struct max77693_muic_info *info,
220 u8 val, bool attached)
221{
222 int ret = 0;
223 u8 ctrl1, ctrl2 = 0;
224
225 if (attached)
226 ctrl1 = val;
227 else
228 ctrl1 = CONTROL1_SW_OPEN;
229
230 ret = max77693_update_reg(info->max77693->regmap_muic,
231 MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK);
232 if (ret < 0) {
233 dev_err(info->dev, "failed to update MUIC register\n");
234 goto out;
235 }
236
237 if (attached)
238 ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */
239 else
240 ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
241
242 ret = max77693_update_reg(info->max77693->regmap_muic,
243 MAX77693_MUIC_REG_CTRL2, ctrl2,
244 CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
245 if (ret < 0) {
246 dev_err(info->dev, "failed to update MUIC register\n");
247 goto out;
248 }
249
250 dev_info(info->dev,
251 "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
252 ctrl1, ctrl2, attached ? "attached" : "detached");
253out:
254 return ret;
255}
256
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900257/*
258 * max77693_muic_get_cable_type - Return cable type and check cable state
259 * @info: the instance including private data of max77693 MUIC
260 * @group: the path according to attached cable
261 * @attached: store cable state and return
262 *
263 * This function check the cable state either attached or detached,
264 * and then divide precise type of cable according to cable group.
265 * - MAX77693_CABLE_GROUP_ADC
266 * - MAX77693_CABLE_GROUP_ADC_GND
267 * - MAX77693_CABLE_GROUP_CHG
268 * - MAX77693_CABLE_GROUP_VBVOLT
269 */
270static int max77693_muic_get_cable_type(struct max77693_muic_info *info,
271 enum max77693_muic_cable_group group, bool *attached)
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900272{
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900273 int cable_type = 0;
274 int adc;
275 int adc1k;
276 int adclow;
277 int vbvolt;
278 int chg_type;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900279
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900280 switch (group) {
281 case MAX77693_CABLE_GROUP_ADC:
282 /*
283 * Read ADC value to check cable type and decide cable state
284 * according to cable type
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900285 */
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900286 adc = info->status[0] & STATUS1_ADC_MASK;
287 adc >>= STATUS1_ADC_SHIFT;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900288
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900289 /*
290 * Check current cable state/cable type and store cable type
291 * (info->prev_cable_type) for handling cable when cable is
292 * detached.
293 */
294 if (adc == MAX77693_MUIC_ADC_OPEN) {
295 *attached = false;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900296
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900297 cable_type = info->prev_cable_type;
298 info->prev_cable_type = MAX77693_MUIC_ADC_OPEN;
299 } else {
300 *attached = true;
301
302 cable_type = info->prev_cable_type = adc;
303 }
304 break;
305 case MAX77693_CABLE_GROUP_ADC_GND:
306 /*
307 * Read ADC value to check cable type and decide cable state
308 * according to cable type
309 */
310 adc = info->status[0] & STATUS1_ADC_MASK;
311 adc >>= STATUS1_ADC_SHIFT;
312
313 /*
314 * Check current cable state/cable type and store cable type
315 * (info->prev_cable_type/_gnd) for handling cable when cable
316 * is detached.
317 */
318 if (adc == MAX77693_MUIC_ADC_OPEN) {
319 *attached = false;
320
321 cable_type = info->prev_cable_type_gnd;
322 info->prev_cable_type_gnd = MAX77693_MUIC_ADC_OPEN;
323 } else {
324 *attached = true;
325
326 adclow = info->status[0] & STATUS1_ADCLOW_MASK;
327 adclow >>= STATUS1_ADCLOW_SHIFT;
328 adc1k = info->status[0] & STATUS1_ADC1K_MASK;
329 adc1k >>= STATUS1_ADC1K_SHIFT;
330
331 vbvolt = info->status[1] & STATUS2_VBVOLT_MASK;
332 vbvolt >>= STATUS2_VBVOLT_SHIFT;
333
334 /**
335 * [0x1][VBVolt][ADCLow][ADC1K]
336 * [0x1 0 0 0 ] : USB_OTG
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900337 * [0x1 1 0 0 ] : USB_OTG_VB
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900338 * [0x1 0 1 0 ] : Audio Video Cable with load
339 * [0x1 0 1 1 ] : MHL without charging connector
340 * [0x1 1 1 1 ] : MHL with charging connector
341 */
342 cable_type = ((0x1 << 8)
343 | (vbvolt << 2)
344 | (adclow << 1)
345 | adc1k);
346
347 info->prev_cable_type = adc;
348 info->prev_cable_type_gnd = cable_type;
349 }
350
351 break;
352 case MAX77693_CABLE_GROUP_CHG:
353 /*
354 * Read charger type to check cable type and decide cable state
355 * according to type of charger cable.
356 */
357 chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
358 chg_type >>= STATUS2_CHGTYP_SHIFT;
359
360 if (chg_type == MAX77693_CHARGER_TYPE_NONE) {
361 *attached = false;
362
363 cable_type = info->prev_chg_type;
364 info->prev_chg_type = MAX77693_CHARGER_TYPE_NONE;
365 } else {
366 *attached = true;
367
368 /*
369 * Check current cable state/cable type and store cable
370 * type(info->prev_chg_type) for handling cable when
371 * charger cable is detached.
372 */
373 cable_type = info->prev_chg_type = chg_type;
374 }
375
376 break;
377 case MAX77693_CABLE_GROUP_VBVOLT:
378 /*
379 * Read ADC value to check cable type and decide cable state
380 * according to cable type
381 */
382 adc = info->status[0] & STATUS1_ADC_MASK;
383 adc >>= STATUS1_ADC_SHIFT;
384 chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
385 chg_type >>= STATUS2_CHGTYP_SHIFT;
386
387 if (adc == MAX77693_MUIC_ADC_OPEN
388 && chg_type == MAX77693_CHARGER_TYPE_NONE)
389 *attached = false;
390 else
391 *attached = true;
392
393 /*
394 * Read vbvolt field, if vbvolt is 1,
395 * this cable is used for charging.
396 */
397 vbvolt = info->status[1] & STATUS2_VBVOLT_MASK;
398 vbvolt >>= STATUS2_VBVOLT_SHIFT;
399
400 cable_type = vbvolt;
401 break;
402 default:
403 dev_err(info->dev, "Unknown cable group (%d)\n", group);
404 cable_type = -EINVAL;
405 break;
406 }
407
408 return cable_type;
409}
410
411static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
412{
413 int cable_type_gnd;
414 int ret = 0;
415 bool attached;
416
417 cable_type_gnd = max77693_muic_get_cable_type(info,
418 MAX77693_CABLE_GROUP_ADC_GND, &attached);
419
420 switch (cable_type_gnd) {
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900421 case MAX77693_MUIC_GND_USB_OTG:
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900422 case MAX77693_MUIC_GND_USB_OTG_VB:
423 /* USB_OTG, PATH: AP_USB */
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900424 ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
425 if (ret < 0)
426 goto out;
427 extcon_set_cable_state(info->edev, "USB-Host", attached);
428 break;
429 case MAX77693_MUIC_GND_AV_CABLE_LOAD:
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900430 /* Audio Video Cable with load, PATH:AUDIO */
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900431 ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
432 if (ret < 0)
433 goto out;
434 extcon_set_cable_state(info->edev,
435 "Audio-video-load", attached);
436 break;
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900437 case MAX77693_MUIC_GND_MHL:
438 case MAX77693_MUIC_GND_MHL_VB:
439 /* MHL or MHL with USB/TA cable */
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900440 extcon_set_cable_state(info->edev, "MHL", attached);
441 break;
442 default:
Peter Meerwaldafcfaa82012-08-23 09:11:47 +0900443 dev_err(info->dev, "failed to detect %s accessory\n",
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900444 attached ? "attached" : "detached");
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900445 ret = -EINVAL;
446 break;
447 }
448
449out:
450 return ret;
451}
452
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900453static int max77693_muic_adc_handler(struct max77693_muic_info *info)
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900454{
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900455 int cable_type;
456 bool attached;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900457 int ret = 0;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900458
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900459 /* Check accessory state which is either detached or attached */
460 cable_type = max77693_muic_get_cable_type(info,
461 MAX77693_CABLE_GROUP_ADC, &attached);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900462
463 dev_info(info->dev,
464 "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900465 attached ? "attached" : "detached", cable_type,
466 info->prev_cable_type);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900467
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900468 switch (cable_type) {
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900469 case MAX77693_MUIC_ADC_GROUND:
470 /* USB_OTG/MHL/Audio */
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900471 max77693_muic_adc_ground_handler(info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900472 break;
473 case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF:
474 case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON:
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900475 case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF:
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900476 /* JIG */
477 ret = max77693_muic_set_path(info, CONTROL1_SW_UART, attached);
478 if (ret < 0)
479 goto out;
480 extcon_set_cable_state(info->edev, "JIG", attached);
481 break;
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900482 case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON:
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900483 case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE:
484 /* Audio Video cable with no-load */
485 ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
486 if (ret < 0)
487 goto out;
488 extcon_set_cable_state(info->edev,
489 "Audio-video-noload", attached);
490 break;
491 case MAX77693_MUIC_ADC_SEND_END_BUTTON:
492 case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON:
493 case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON:
494 case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON:
495 case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON:
496 case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON:
497 case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON:
498 case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON:
499 case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON:
500 case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON:
501 case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON:
502 case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON:
503 case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON:
504 case MAX77693_MUIC_ADC_RESERVED_ACC_1:
505 case MAX77693_MUIC_ADC_RESERVED_ACC_2:
506 case MAX77693_MUIC_ADC_RESERVED_ACC_3:
507 case MAX77693_MUIC_ADC_RESERVED_ACC_4:
508 case MAX77693_MUIC_ADC_RESERVED_ACC_5:
509 case MAX77693_MUIC_ADC_CEA936_AUDIO:
510 case MAX77693_MUIC_ADC_PHONE_POWERED_DEV:
511 case MAX77693_MUIC_ADC_TTY_CONVERTER:
512 case MAX77693_MUIC_ADC_UART_CABLE:
513 case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG:
514 case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD:
515 case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG:
516 /* This accessory isn't used in general case if it is specially
517 needed to detect additional accessory, should implement
518 proper operation when this accessory is attached/detached. */
519 dev_info(info->dev,
520 "accessory is %s but it isn't used (adc:0x%x)\n",
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900521 attached ? "attached" : "detached", cable_type);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900522 goto out;
523 default:
524 dev_err(info->dev,
525 "failed to detect %s accessory (adc:0x%x)\n",
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900526 attached ? "attached" : "detached", cable_type);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900527 ret = -EINVAL;
528 goto out;
529 }
530
531out:
532 return ret;
533}
534
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900535static int max77693_muic_chg_handler(struct max77693_muic_info *info)
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900536{
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900537 int chg_type;
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900538 int cable_type_gnd;
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900539 bool attached;
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900540 bool cable_attached;
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900541 int ret = 0;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900542
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900543 chg_type = max77693_muic_get_cable_type(info,
544 MAX77693_CABLE_GROUP_CHG, &attached);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900545
546 dev_info(info->dev,
547 "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
548 attached ? "attached" : "detached",
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900549 chg_type, info->prev_chg_type);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900550
551 switch (chg_type) {
552 case MAX77693_CHARGER_TYPE_USB:
Chanwoo Choi06bed0a2012-11-27 11:30:35 +0900553 cable_type_gnd = max77693_muic_get_cable_type(info,
554 MAX77693_CABLE_GROUP_ADC_GND,
555 &cable_attached);
556
557 switch (cable_type_gnd) {
558 case MAX77693_MUIC_GND_MHL:
559 case MAX77693_MUIC_GND_MHL_VB:
560 /*
561 * USB/TA with MHL cable
562 * - MHL cable, which connect micro USB or TA cable,
563 * is used to charging battery. So, extcon driver check
564 * charging type whether micro USB or TA cable is
565 * connected to MHL cable when extcon driver detect MHL
566 * cable.
567 */
568 extcon_set_cable_state(info->edev, "MHL_TA", attached);
569
570 if (!cable_attached)
571 extcon_set_cable_state(info->edev,
572 "MHL", false);
573 break;
574 default:
575 /* Only USB cable, PATH:AP_USB */
576 ret = max77693_muic_set_path(info, CONTROL1_SW_USB,
577 attached);
578 if (ret < 0)
579 goto out;
580 extcon_set_cable_state(info->edev, "USB", attached);
581 }
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900582 break;
583 case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
584 extcon_set_cable_state(info->edev,
585 "Charge-downstream", attached);
586 break;
587 case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
588 extcon_set_cable_state(info->edev, "TA", attached);
589 break;
590 case MAX77693_CHARGER_TYPE_APPLE_500MA:
591 extcon_set_cable_state(info->edev, "Slow-charger", attached);
592 break;
593 case MAX77693_CHARGER_TYPE_APPLE_1A_2A:
594 extcon_set_cable_state(info->edev, "Fast-charger", attached);
595 break;
596 case MAX77693_CHARGER_TYPE_DEAD_BATTERY:
597 break;
598 default:
599 dev_err(info->dev,
600 "failed to detect %s accessory (chg_type:0x%x)\n",
601 attached ? "attached" : "detached", chg_type);
602 ret = -EINVAL;
603 goto out;
604 }
605
606out:
607 return ret;
608}
609
610static void max77693_muic_irq_work(struct work_struct *work)
611{
612 struct max77693_muic_info *info = container_of(work,
613 struct max77693_muic_info, irq_work);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900614 int irq_type = -1;
615 int i, ret = 0;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900616
617 if (!info->edev)
618 return;
619
620 mutex_lock(&info->mutex);
621
622 for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++)
623 if (info->irq == muic_irqs[i].virq)
624 irq_type = muic_irqs[i].irq;
625
626 ret = max77693_bulk_read(info->max77693->regmap_muic,
627 MAX77693_MUIC_REG_STATUS1, 2, info->status);
628 if (ret) {
629 dev_err(info->dev, "failed to read MUIC register\n");
630 mutex_unlock(&info->mutex);
631 return;
632 }
633
634 switch (irq_type) {
635 case MAX77693_MUIC_IRQ_INT1_ADC:
636 case MAX77693_MUIC_IRQ_INT1_ADC_LOW:
637 case MAX77693_MUIC_IRQ_INT1_ADC_ERR:
638 case MAX77693_MUIC_IRQ_INT1_ADC1K:
639 /* Handle all of accessory except for
640 type of charger accessory */
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900641 ret = max77693_muic_adc_handler(info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900642 break;
643 case MAX77693_MUIC_IRQ_INT2_CHGTYP:
644 case MAX77693_MUIC_IRQ_INT2_CHGDETREUN:
645 case MAX77693_MUIC_IRQ_INT2_DCDTMR:
646 case MAX77693_MUIC_IRQ_INT2_DXOVP:
647 case MAX77693_MUIC_IRQ_INT2_VBVOLT:
648 case MAX77693_MUIC_IRQ_INT2_VIDRM:
649 /* Handle charger accessory */
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900650 ret = max77693_muic_chg_handler(info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900651 break;
652 case MAX77693_MUIC_IRQ_INT3_EOC:
653 case MAX77693_MUIC_IRQ_INT3_CGMBC:
654 case MAX77693_MUIC_IRQ_INT3_OVP:
655 case MAX77693_MUIC_IRQ_INT3_MBCCHG_ERR:
656 case MAX77693_MUIC_IRQ_INT3_CHG_ENABLED:
657 case MAX77693_MUIC_IRQ_INT3_BAT_DET:
658 break;
659 default:
660 dev_err(info->dev, "muic interrupt: irq %d occurred\n",
661 irq_type);
662 break;
663 }
664
665 if (ret < 0)
666 dev_err(info->dev, "failed to handle MUIC interrupt\n");
667
668 mutex_unlock(&info->mutex);
669
670 return;
671}
672
673static irqreturn_t max77693_muic_irq_handler(int irq, void *data)
674{
675 struct max77693_muic_info *info = data;
676
677 info->irq = irq;
678 schedule_work(&info->irq_work);
679
680 return IRQ_HANDLED;
681}
682
683static struct regmap_config max77693_muic_regmap_config = {
684 .reg_bits = 8,
685 .val_bits = 8,
686};
687
688static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
689{
690 int ret = 0;
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900691 int adc;
692 int chg_type;
693 bool attached;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900694
695 mutex_lock(&info->mutex);
696
697 /* Read STATUSx register to detect accessory */
698 ret = max77693_bulk_read(info->max77693->regmap_muic,
699 MAX77693_MUIC_REG_STATUS1, 2, info->status);
700 if (ret) {
701 dev_err(info->dev, "failed to read MUIC register\n");
702 mutex_unlock(&info->mutex);
703 return -EINVAL;
704 }
705
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900706 adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC,
707 &attached);
708 if (attached && adc != MAX77693_MUIC_ADC_OPEN) {
709 ret = max77693_muic_adc_handler(info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900710 if (ret < 0)
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900711 dev_err(info->dev, "Cannot detect accessory\n");
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900712 }
713
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900714 chg_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_CHG,
715 &attached);
716 if (attached && chg_type != MAX77693_CHARGER_TYPE_NONE) {
717 ret = max77693_muic_chg_handler(info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900718 if (ret < 0)
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900719 dev_err(info->dev, "Cannot detect charger accessory\n");
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900720 }
721
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900722 mutex_unlock(&info->mutex);
Chanwoo Choi154f757f2012-11-27 09:40:32 +0900723
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900724 return ret;
725}
726
Bill Pemberton44f34fd2012-11-19 13:23:21 -0500727static int max77693_muic_probe(struct platform_device *pdev)
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900728{
729 struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
Chanwoo Choif8457d52012-10-08 14:41:49 +0900730 struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
731 struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900732 struct max77693_muic_info *info;
733 int ret, i;
734 u8 id;
735
Sachin Kamatf4bb5cb2012-11-20 15:46:50 +0900736 info = devm_kzalloc(&pdev->dev, sizeof(struct max77693_muic_info),
737 GFP_KERNEL);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900738 if (!info) {
739 dev_err(&pdev->dev, "failed to allocate memory\n");
Sachin Kamatf4bb5cb2012-11-20 15:46:50 +0900740 return -ENOMEM;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900741 }
742 info->dev = &pdev->dev;
743 info->max77693 = max77693;
Sachin Kamat1967fa02012-11-21 10:04:58 +0530744 if (info->max77693->regmap_muic) {
Chanwoo Choib186b122012-08-21 15:16:23 +0900745 dev_dbg(&pdev->dev, "allocate register map\n");
Sachin Kamat1967fa02012-11-21 10:04:58 +0530746 } else {
Chanwoo Choib186b122012-08-21 15:16:23 +0900747 info->max77693->regmap_muic = devm_regmap_init_i2c(
748 info->max77693->muic,
749 &max77693_muic_regmap_config);
750 if (IS_ERR(info->max77693->regmap_muic)) {
751 ret = PTR_ERR(info->max77693->regmap_muic);
752 dev_err(max77693->dev,
753 "failed to allocate register map: %d\n", ret);
Sachin Kamat3bf742f2012-11-21 10:04:57 +0530754 return ret;
Chanwoo Choib186b122012-08-21 15:16:23 +0900755 }
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900756 }
757 platform_set_drvdata(pdev, info);
758 mutex_init(&info->mutex);
759
760 INIT_WORK(&info->irq_work, max77693_muic_irq_work);
761
762 /* Support irq domain for MAX77693 MUIC device */
763 for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
764 struct max77693_muic_irq *muic_irq = &muic_irqs[i];
Sachin Kamat00af4b12012-11-20 15:46:44 +0900765 unsigned int virq = 0;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900766
767 virq = irq_create_mapping(max77693->irq_domain, muic_irq->irq);
Sachin Kamat00af4b12012-11-20 15:46:44 +0900768 if (!virq) {
769 ret = -EINVAL;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900770 goto err_irq;
Sachin Kamat00af4b12012-11-20 15:46:44 +0900771 }
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900772 muic_irq->virq = virq;
773
774 ret = request_threaded_irq(virq, NULL,
775 max77693_muic_irq_handler,
Fengguang Wuaa493122012-09-06 11:56:35 +0800776 IRQF_ONESHOT, muic_irq->name, info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900777 if (ret) {
778 dev_err(&pdev->dev,
779 "failed: irq request (IRQ: %d,"
780 " error :%d)\n",
781 muic_irq->irq, ret);
782
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900783 goto err_irq;
784 }
785 }
786
787 /* Initialize extcon device */
Sachin Kamatf4bb5cb2012-11-20 15:46:50 +0900788 info->edev = devm_kzalloc(&pdev->dev, sizeof(struct extcon_dev),
789 GFP_KERNEL);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900790 if (!info->edev) {
791 dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
792 ret = -ENOMEM;
793 goto err_irq;
794 }
795 info->edev->name = DEV_NAME;
796 info->edev->supported_cable = max77693_extcon_cable;
797 ret = extcon_dev_register(info->edev, NULL);
798 if (ret) {
799 dev_err(&pdev->dev, "failed to register extcon device\n");
Sachin Kamatf4bb5cb2012-11-20 15:46:50 +0900800 goto err_irq;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900801 }
802
Chanwoo Choif8457d52012-10-08 14:41:49 +0900803 /* Initialize MUIC register by using platform data */
804 for (i = 0 ; i < muic_pdata->num_init_data ; i++) {
805 enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR;
806
807 max77693_write_reg(info->max77693->regmap_muic,
808 muic_pdata->init_data[i].addr,
809 muic_pdata->init_data[i].data);
810
811 switch (muic_pdata->init_data[i].addr) {
812 case MAX77693_MUIC_REG_INTMASK1:
813 irq_src = MUIC_INT1;
814 break;
815 case MAX77693_MUIC_REG_INTMASK2:
816 irq_src = MUIC_INT2;
817 break;
818 case MAX77693_MUIC_REG_INTMASK3:
819 irq_src = MUIC_INT3;
820 break;
821 }
822
823 if (irq_src < MAX77693_IRQ_GROUP_NR)
824 info->max77693->irq_masks_cur[irq_src]
825 = muic_pdata->init_data[i].data;
826 }
827
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900828 /* Check revision number of MUIC device*/
829 ret = max77693_read_reg(info->max77693->regmap_muic,
830 MAX77693_MUIC_REG_ID, &id);
831 if (ret < 0) {
832 dev_err(&pdev->dev, "failed to read revision number\n");
Sachin Kamatf4bb5cb2012-11-20 15:46:50 +0900833 goto err_irq;
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900834 }
835 dev_info(info->dev, "device ID : 0x%x\n", id);
836
837 /* Set ADC debounce time */
838 max77693_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
839
840 /* Detect accessory on boot */
841 max77693_muic_detect_accessory(info);
842
843 return ret;
844
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900845err_irq:
Sachin Kamat00af4b12012-11-20 15:46:44 +0900846 while (--i >= 0)
847 free_irq(muic_irqs[i].virq, info);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900848 return ret;
849}
850
Bill Pemberton93ed0322012-11-19 13:25:49 -0500851static int max77693_muic_remove(struct platform_device *pdev)
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900852{
853 struct max77693_muic_info *info = platform_get_drvdata(pdev);
854 int i;
855
856 for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
857 free_irq(muic_irqs[i].virq, info);
858 cancel_work_sync(&info->irq_work);
859 extcon_dev_unregister(info->edev);
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900860
861 return 0;
862}
863
864static struct platform_driver max77693_muic_driver = {
865 .driver = {
866 .name = DEV_NAME,
867 .owner = THIS_MODULE,
868 },
869 .probe = max77693_muic_probe,
Bill Pemberton5f7e2222012-11-19 13:20:06 -0500870 .remove = max77693_muic_remove,
Chanwoo Choidb1b9032012-07-17 13:28:28 +0900871};
872
873module_platform_driver(max77693_muic_driver);
874
875MODULE_DESCRIPTION("Maxim MAX77693 Extcon driver");
876MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
877MODULE_LICENSE("GPL");
878MODULE_ALIAS("platform:extcon-max77693");