11213a366SKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0+
21213a366SKrzysztof Kozlowski //
31213a366SKrzysztof Kozlowski // extcon-max77693.c - MAX77693 extcon driver to support MAX77693 MUIC
41213a366SKrzysztof Kozlowski //
51213a366SKrzysztof Kozlowski // Copyright (C) 2012 Samsung Electrnoics
61213a366SKrzysztof Kozlowski // Chanwoo Choi <cw00.choi@samsung.com>
7db1b9037SChanwoo Choi
8*74047eaaSMatti Vaittinen #include <linux/devm-helpers.h>
9db1b9037SChanwoo Choi #include <linux/kernel.h>
10db1b9037SChanwoo Choi #include <linux/module.h>
11db1b9037SChanwoo Choi #include <linux/i2c.h>
12db1b9037SChanwoo Choi #include <linux/slab.h>
1339bf369eSChanwoo Choi #include <linux/input.h>
14db1b9037SChanwoo Choi #include <linux/interrupt.h>
15db1b9037SChanwoo Choi #include <linux/err.h>
16db1b9037SChanwoo Choi #include <linux/platform_device.h>
17db1b9037SChanwoo Choi #include <linux/mfd/max77693.h>
1861b305cdSKrzysztof Kozlowski #include <linux/mfd/max77693-common.h>
19db1b9037SChanwoo Choi #include <linux/mfd/max77693-private.h>
20176aa360SChanwoo Choi #include <linux/extcon-provider.h>
21db1b9037SChanwoo Choi #include <linux/regmap.h>
22db1b9037SChanwoo Choi #include <linux/irqdomain.h>
23db1b9037SChanwoo Choi
24db1b9037SChanwoo Choi #define DEV_NAME "max77693-muic"
25297620fdSChanwoo Choi #define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
26db1b9037SChanwoo Choi
270ec83bd2SChanwoo Choi /*
280ec83bd2SChanwoo Choi * Default value of MAX77693 register to bring up MUIC device.
290ec83bd2SChanwoo Choi * If user don't set some initial value for MUIC device through platform data,
300ec83bd2SChanwoo Choi * extcon-max77693 driver use 'default_init_data' to bring up base operation
310ec83bd2SChanwoo Choi * of MAX77693 MUIC device.
320ec83bd2SChanwoo Choi */
33813b4516SSachin Kamat static struct max77693_reg_data default_init_data[] = {
340ec83bd2SChanwoo Choi {
350ec83bd2SChanwoo Choi /* STATUS2 - [3]ChgDetRun */
360ec83bd2SChanwoo Choi .addr = MAX77693_MUIC_REG_STATUS2,
37cceb433aSKrzysztof Kozlowski .data = MAX77693_STATUS2_CHGDETRUN_MASK,
380ec83bd2SChanwoo Choi }, {
390ec83bd2SChanwoo Choi /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */
400ec83bd2SChanwoo Choi .addr = MAX77693_MUIC_REG_INTMASK1,
410ec83bd2SChanwoo Choi .data = INTMASK1_ADC1K_MASK
420ec83bd2SChanwoo Choi | INTMASK1_ADC_MASK,
430ec83bd2SChanwoo Choi }, {
440ec83bd2SChanwoo Choi /* INTMASK2 - Unmask [0]ChgTypM */
450ec83bd2SChanwoo Choi .addr = MAX77693_MUIC_REG_INTMASK2,
460ec83bd2SChanwoo Choi .data = INTMASK2_CHGTYP_MASK,
470ec83bd2SChanwoo Choi }, {
480ec83bd2SChanwoo Choi /* INTMASK3 - Mask all of interrupts */
490ec83bd2SChanwoo Choi .addr = MAX77693_MUIC_REG_INTMASK3,
500ec83bd2SChanwoo Choi .data = 0x0,
510ec83bd2SChanwoo Choi }, {
520ec83bd2SChanwoo Choi /* CDETCTRL2 */
530ec83bd2SChanwoo Choi .addr = MAX77693_MUIC_REG_CDETCTRL2,
540ec83bd2SChanwoo Choi .data = CDETCTRL2_VIDRMEN_MASK
550ec83bd2SChanwoo Choi | CDETCTRL2_DXOVPEN_MASK,
560ec83bd2SChanwoo Choi },
570ec83bd2SChanwoo Choi };
580ec83bd2SChanwoo Choi
59db1b9037SChanwoo Choi enum max77693_muic_adc_debounce_time {
60db1b9037SChanwoo Choi ADC_DEBOUNCE_TIME_5MS = 0,
61db1b9037SChanwoo Choi ADC_DEBOUNCE_TIME_10MS,
62db1b9037SChanwoo Choi ADC_DEBOUNCE_TIME_25MS,
63db1b9037SChanwoo Choi ADC_DEBOUNCE_TIME_38_62MS,
64db1b9037SChanwoo Choi };
65db1b9037SChanwoo Choi
66db1b9037SChanwoo Choi struct max77693_muic_info {
67db1b9037SChanwoo Choi struct device *dev;
68db1b9037SChanwoo Choi struct max77693_dev *max77693;
69db1b9037SChanwoo Choi struct extcon_dev *edev;
70154f757fSChanwoo Choi int prev_cable_type;
71154f757fSChanwoo Choi int prev_cable_type_gnd;
72db1b9037SChanwoo Choi int prev_chg_type;
7339bf369eSChanwoo Choi int prev_button_type;
74db1b9037SChanwoo Choi u8 status[2];
75db1b9037SChanwoo Choi
76db1b9037SChanwoo Choi int irq;
77db1b9037SChanwoo Choi struct work_struct irq_work;
78db1b9037SChanwoo Choi struct mutex mutex;
7939bf369eSChanwoo Choi
80297620fdSChanwoo Choi /*
81297620fdSChanwoo Choi * Use delayed workqueue to detect cable state and then
82297620fdSChanwoo Choi * notify cable state to notifiee/platform through uevent.
83297620fdSChanwoo Choi * After completing the booting of platform, the extcon provider
84297620fdSChanwoo Choi * driver should notify cable state to upper layer.
85297620fdSChanwoo Choi */
86297620fdSChanwoo Choi struct delayed_work wq_detcable;
87297620fdSChanwoo Choi
8839bf369eSChanwoo Choi /* Button of dock device */
8939bf369eSChanwoo Choi struct input_dev *dock;
902b75799fSChanwoo Choi
912b75799fSChanwoo Choi /*
922b75799fSChanwoo Choi * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
932b75799fSChanwoo Choi * h/w path of COMP2/COMN1 on CONTROL1 register.
942b75799fSChanwoo Choi */
952b75799fSChanwoo Choi int path_usb;
962b75799fSChanwoo Choi int path_uart;
97db1b9037SChanwoo Choi };
98db1b9037SChanwoo Choi
99154f757fSChanwoo Choi enum max77693_muic_cable_group {
100154f757fSChanwoo Choi MAX77693_CABLE_GROUP_ADC = 0,
101154f757fSChanwoo Choi MAX77693_CABLE_GROUP_ADC_GND,
102154f757fSChanwoo Choi MAX77693_CABLE_GROUP_CHG,
103154f757fSChanwoo Choi MAX77693_CABLE_GROUP_VBVOLT,
104154f757fSChanwoo Choi };
105154f757fSChanwoo Choi
106db1b9037SChanwoo Choi enum max77693_muic_charger_type {
107db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_NONE = 0,
108db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_USB,
109db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT,
110db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_DEDICATED_CHG,
111db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_APPLE_500MA,
112db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_APPLE_1A_2A,
113db1b9037SChanwoo Choi MAX77693_CHARGER_TYPE_DEAD_BATTERY = 7,
114db1b9037SChanwoo Choi };
115db1b9037SChanwoo Choi
116db1b9037SChanwoo Choi /**
117db1b9037SChanwoo Choi * struct max77693_muic_irq
118db1b9037SChanwoo Choi * @irq: the index of irq list of MUIC device.
119db1b9037SChanwoo Choi * @name: the name of irq.
120db1b9037SChanwoo Choi * @virq: the virtual irq to use irq domain
121db1b9037SChanwoo Choi */
122db1b9037SChanwoo Choi struct max77693_muic_irq {
123db1b9037SChanwoo Choi unsigned int irq;
124db1b9037SChanwoo Choi const char *name;
125db1b9037SChanwoo Choi unsigned int virq;
126db1b9037SChanwoo Choi };
127db1b9037SChanwoo Choi
128db1b9037SChanwoo Choi static struct max77693_muic_irq muic_irqs[] = {
129db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT1_ADC, "muic-ADC" },
130db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT1_ADC_LOW, "muic-ADCLOW" },
131db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT1_ADC_ERR, "muic-ADCError" },
132db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT1_ADC1K, "muic-ADC1K" },
133db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
134db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT2_CHGDETREUN, "muic-CHGDETREUN" },
135db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
136db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT2_DXOVP, "muic-DXOVP" },
137db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
138db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT2_VIDRM, "muic-VIDRM" },
139db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT3_EOC, "muic-EOC" },
140db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT3_CGMBC, "muic-CGMBC" },
141db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT3_OVP, "muic-OVP" },
142db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT3_MBCCHG_ERR, "muic-MBCCHG_ERR" },
143db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT3_CHG_ENABLED, "muic-CHG_ENABLED" },
144db1b9037SChanwoo Choi { MAX77693_MUIC_IRQ_INT3_BAT_DET, "muic-BAT_DET" },
145db1b9037SChanwoo Choi };
146db1b9037SChanwoo Choi
147db1b9037SChanwoo Choi /* Define supported accessory type */
148db1b9037SChanwoo Choi enum max77693_muic_acc_type {
149db1b9037SChanwoo Choi MAX77693_MUIC_ADC_GROUND = 0x0,
150db1b9037SChanwoo Choi MAX77693_MUIC_ADC_SEND_END_BUTTON,
151db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S1_BUTTON,
152db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S2_BUTTON,
153db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S3_BUTTON,
154db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S4_BUTTON,
155db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S5_BUTTON,
156db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S6_BUTTON,
157db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S7_BUTTON,
158db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S8_BUTTON,
159db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S9_BUTTON,
160db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S10_BUTTON,
161db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S11_BUTTON,
162db1b9037SChanwoo Choi MAX77693_MUIC_ADC_REMOTE_S12_BUTTON,
163db1b9037SChanwoo Choi MAX77693_MUIC_ADC_RESERVED_ACC_1,
164db1b9037SChanwoo Choi MAX77693_MUIC_ADC_RESERVED_ACC_2,
165db1b9037SChanwoo Choi MAX77693_MUIC_ADC_RESERVED_ACC_3,
166db1b9037SChanwoo Choi MAX77693_MUIC_ADC_RESERVED_ACC_4,
167db1b9037SChanwoo Choi MAX77693_MUIC_ADC_RESERVED_ACC_5,
168db1b9037SChanwoo Choi MAX77693_MUIC_ADC_CEA936_AUDIO,
169db1b9037SChanwoo Choi MAX77693_MUIC_ADC_PHONE_POWERED_DEV,
170db1b9037SChanwoo Choi MAX77693_MUIC_ADC_TTY_CONVERTER,
171db1b9037SChanwoo Choi MAX77693_MUIC_ADC_UART_CABLE,
172db1b9037SChanwoo Choi MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG,
173db1b9037SChanwoo Choi MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF,
174db1b9037SChanwoo Choi MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON,
175db1b9037SChanwoo Choi MAX77693_MUIC_ADC_AV_CABLE_NOLOAD,
176db1b9037SChanwoo Choi MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG,
177db1b9037SChanwoo Choi MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF,
178db1b9037SChanwoo Choi MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON,
179db1b9037SChanwoo Choi MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE,
180db1b9037SChanwoo Choi MAX77693_MUIC_ADC_OPEN,
181db1b9037SChanwoo Choi
182af57fa4dSSrikant Ritolia /*
183af57fa4dSSrikant Ritolia * The below accessories have same ADC value so ADCLow and
184af57fa4dSSrikant Ritolia * ADC1K bit is used to separate specific accessory.
185af57fa4dSSrikant Ritolia */
186c2275d2fSChanwoo Choi /* ADC|VBVolot|ADCLow|ADC1K| */
1874c883abeSJaewon Kim MAX77693_MUIC_GND_USB_HOST = 0x100, /* 0x0| 0| 0| 0| */
1884c883abeSJaewon Kim MAX77693_MUIC_GND_USB_HOST_VB = 0x104, /* 0x0| 1| 0| 0| */
189c2275d2fSChanwoo Choi MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* 0x0| 0| 1| 0| */
190c2275d2fSChanwoo Choi MAX77693_MUIC_GND_MHL = 0x103, /* 0x0| 0| 1| 1| */
191c2275d2fSChanwoo Choi MAX77693_MUIC_GND_MHL_VB = 0x107, /* 0x0| 1| 1| 1| */
192db1b9037SChanwoo Choi };
193db1b9037SChanwoo Choi
194c2275d2fSChanwoo Choi /*
195c2275d2fSChanwoo Choi * MAX77693 MUIC device support below list of accessories(external connector)
196c2275d2fSChanwoo Choi */
19773b6ecdbSChanwoo Choi static const unsigned int max77693_extcon_cable[] = {
1982a9de9c0SChanwoo Choi EXTCON_USB,
1992a9de9c0SChanwoo Choi EXTCON_USB_HOST,
2008b45b6a0SChanwoo Choi EXTCON_CHG_USB_SDP,
20111eecf91SChanwoo Choi EXTCON_CHG_USB_DCP,
20211eecf91SChanwoo Choi EXTCON_CHG_USB_FAST,
20311eecf91SChanwoo Choi EXTCON_CHG_USB_SLOW,
20411eecf91SChanwoo Choi EXTCON_CHG_USB_CDP,
20511eecf91SChanwoo Choi EXTCON_DISP_MHL,
2062a9de9c0SChanwoo Choi EXTCON_JIG,
2072a9de9c0SChanwoo Choi EXTCON_DOCK,
2082a9de9c0SChanwoo Choi EXTCON_NONE,
209db1b9037SChanwoo Choi };
210db1b9037SChanwoo Choi
211154f757fSChanwoo Choi /*
212154f757fSChanwoo Choi * max77693_muic_set_debounce_time - Set the debounce time of ADC
213154f757fSChanwoo Choi * @info: the instance including private data of max77693 MUIC
214154f757fSChanwoo Choi * @time: the debounce time of ADC
215154f757fSChanwoo Choi */
max77693_muic_set_debounce_time(struct max77693_muic_info * info,enum max77693_muic_adc_debounce_time time)216db1b9037SChanwoo Choi static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
217db1b9037SChanwoo Choi enum max77693_muic_adc_debounce_time time)
218db1b9037SChanwoo Choi {
219bf2627d6SAxel Lin int ret;
220db1b9037SChanwoo Choi
221db1b9037SChanwoo Choi switch (time) {
222db1b9037SChanwoo Choi case ADC_DEBOUNCE_TIME_5MS:
223db1b9037SChanwoo Choi case ADC_DEBOUNCE_TIME_10MS:
224db1b9037SChanwoo Choi case ADC_DEBOUNCE_TIME_25MS:
225db1b9037SChanwoo Choi case ADC_DEBOUNCE_TIME_38_62MS:
226dc6048d7SJonghwa Lee /*
227dc6048d7SJonghwa Lee * Don't touch BTLDset, JIGset when you want to change adc
228dc6048d7SJonghwa Lee * debounce time. If it writes other than 0 to BTLDset, JIGset
229dc6048d7SJonghwa Lee * muic device will be reset and loose current state.
230dc6048d7SJonghwa Lee */
231dc6048d7SJonghwa Lee ret = regmap_write(info->max77693->regmap_muic,
232bf2627d6SAxel Lin MAX77693_MUIC_REG_CTRL3,
233cceb433aSKrzysztof Kozlowski time << MAX77693_CONTROL3_ADCDBSET_SHIFT);
23419d3243eSChanwoo Choi if (ret) {
235db1b9037SChanwoo Choi dev_err(info->dev, "failed to set ADC debounce time\n");
236c2536543SSachin Kamat return ret;
23719d3243eSChanwoo Choi }
238db1b9037SChanwoo Choi break;
239db1b9037SChanwoo Choi default:
240db1b9037SChanwoo Choi dev_err(info->dev, "invalid ADC debounce time\n");
24119d3243eSChanwoo Choi return -EINVAL;
242db1b9037SChanwoo Choi }
243db1b9037SChanwoo Choi
24419d3243eSChanwoo Choi return 0;
245db1b9037SChanwoo Choi };
246db1b9037SChanwoo Choi
247154f757fSChanwoo Choi /*
248154f757fSChanwoo Choi * max77693_muic_set_path - Set hardware line according to attached cable
249154f757fSChanwoo Choi * @info: the instance including private data of max77693 MUIC
250154f757fSChanwoo Choi * @value: the path according to attached cable
251154f757fSChanwoo Choi * @attached: the state of cable (true:attached, false:detached)
252154f757fSChanwoo Choi *
253154f757fSChanwoo Choi * The max77693 MUIC device share outside H/W line among a varity of cables
254154f757fSChanwoo Choi * so, this function set internal path of H/W line according to the type of
255154f757fSChanwoo Choi * attached cable.
256154f757fSChanwoo Choi */
max77693_muic_set_path(struct max77693_muic_info * info,u8 val,bool attached)257db1b9037SChanwoo Choi static int max77693_muic_set_path(struct max77693_muic_info *info,
258db1b9037SChanwoo Choi u8 val, bool attached)
259db1b9037SChanwoo Choi {
2602d18baf6SMarkus Elfring int ret;
261d0540f91SRobert Baldyga unsigned int ctrl1, ctrl2 = 0;
262db1b9037SChanwoo Choi
263db1b9037SChanwoo Choi if (attached)
264db1b9037SChanwoo Choi ctrl1 = val;
265db1b9037SChanwoo Choi else
266cceb433aSKrzysztof Kozlowski ctrl1 = MAX77693_CONTROL1_SW_OPEN;
267db1b9037SChanwoo Choi
268d0540f91SRobert Baldyga ret = regmap_update_bits(info->max77693->regmap_muic,
269d0540f91SRobert Baldyga MAX77693_MUIC_REG_CTRL1, COMP_SW_MASK, ctrl1);
270db1b9037SChanwoo Choi if (ret < 0) {
271db1b9037SChanwoo Choi dev_err(info->dev, "failed to update MUIC register\n");
272c2536543SSachin Kamat return ret;
273db1b9037SChanwoo Choi }
274db1b9037SChanwoo Choi
275db1b9037SChanwoo Choi if (attached)
276cceb433aSKrzysztof Kozlowski ctrl2 |= MAX77693_CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */
277db1b9037SChanwoo Choi else
278cceb433aSKrzysztof Kozlowski ctrl2 |= MAX77693_CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
279db1b9037SChanwoo Choi
280d0540f91SRobert Baldyga ret = regmap_update_bits(info->max77693->regmap_muic,
281d0540f91SRobert Baldyga MAX77693_MUIC_REG_CTRL2,
282cceb433aSKrzysztof Kozlowski MAX77693_CONTROL2_LOWPWR_MASK | MAX77693_CONTROL2_CPEN_MASK,
283cceb433aSKrzysztof Kozlowski ctrl2);
284db1b9037SChanwoo Choi if (ret < 0) {
285db1b9037SChanwoo Choi dev_err(info->dev, "failed to update MUIC register\n");
286c2536543SSachin Kamat return ret;
287db1b9037SChanwoo Choi }
288db1b9037SChanwoo Choi
289db1b9037SChanwoo Choi dev_info(info->dev,
290db1b9037SChanwoo Choi "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
291db1b9037SChanwoo Choi ctrl1, ctrl2, attached ? "attached" : "detached");
29219d3243eSChanwoo Choi
29319d3243eSChanwoo Choi return 0;
294db1b9037SChanwoo Choi }
295db1b9037SChanwoo Choi
296154f757fSChanwoo Choi /*
297154f757fSChanwoo Choi * max77693_muic_get_cable_type - Return cable type and check cable state
298154f757fSChanwoo Choi * @info: the instance including private data of max77693 MUIC
299154f757fSChanwoo Choi * @group: the path according to attached cable
300154f757fSChanwoo Choi * @attached: store cable state and return
301154f757fSChanwoo Choi *
302154f757fSChanwoo Choi * This function check the cable state either attached or detached,
303154f757fSChanwoo Choi * and then divide precise type of cable according to cable group.
304154f757fSChanwoo Choi * - MAX77693_CABLE_GROUP_ADC
305154f757fSChanwoo Choi * - MAX77693_CABLE_GROUP_ADC_GND
306154f757fSChanwoo Choi * - MAX77693_CABLE_GROUP_CHG
307154f757fSChanwoo Choi * - MAX77693_CABLE_GROUP_VBVOLT
308154f757fSChanwoo Choi */
max77693_muic_get_cable_type(struct max77693_muic_info * info,enum max77693_muic_cable_group group,bool * attached)309154f757fSChanwoo Choi static int max77693_muic_get_cable_type(struct max77693_muic_info *info,
310154f757fSChanwoo Choi enum max77693_muic_cable_group group, bool *attached)
311db1b9037SChanwoo Choi {
312154f757fSChanwoo Choi int cable_type = 0;
313154f757fSChanwoo Choi int adc;
314154f757fSChanwoo Choi int adc1k;
315154f757fSChanwoo Choi int adclow;
316154f757fSChanwoo Choi int vbvolt;
317154f757fSChanwoo Choi int chg_type;
318db1b9037SChanwoo Choi
319154f757fSChanwoo Choi switch (group) {
320154f757fSChanwoo Choi case MAX77693_CABLE_GROUP_ADC:
321154f757fSChanwoo Choi /*
322154f757fSChanwoo Choi * Read ADC value to check cable type and decide cable state
323154f757fSChanwoo Choi * according to cable type
324154f757fSChanwoo Choi */
325cceb433aSKrzysztof Kozlowski adc = info->status[0] & MAX77693_STATUS1_ADC_MASK;
326cceb433aSKrzysztof Kozlowski adc >>= MAX77693_STATUS1_ADC_SHIFT;
327154f757fSChanwoo Choi
328154f757fSChanwoo Choi /*
329154f757fSChanwoo Choi * Check current cable state/cable type and store cable type
330154f757fSChanwoo Choi * (info->prev_cable_type) for handling cable when cable is
331154f757fSChanwoo Choi * detached.
332154f757fSChanwoo Choi */
333154f757fSChanwoo Choi if (adc == MAX77693_MUIC_ADC_OPEN) {
334154f757fSChanwoo Choi *attached = false;
335154f757fSChanwoo Choi
336154f757fSChanwoo Choi cable_type = info->prev_cable_type;
337154f757fSChanwoo Choi info->prev_cable_type = MAX77693_MUIC_ADC_OPEN;
338154f757fSChanwoo Choi } else {
339154f757fSChanwoo Choi *attached = true;
340154f757fSChanwoo Choi
341154f757fSChanwoo Choi cable_type = info->prev_cable_type = adc;
342154f757fSChanwoo Choi }
343154f757fSChanwoo Choi break;
344154f757fSChanwoo Choi case MAX77693_CABLE_GROUP_ADC_GND:
345154f757fSChanwoo Choi /*
346154f757fSChanwoo Choi * Read ADC value to check cable type and decide cable state
347154f757fSChanwoo Choi * according to cable type
348154f757fSChanwoo Choi */
349cceb433aSKrzysztof Kozlowski adc = info->status[0] & MAX77693_STATUS1_ADC_MASK;
350cceb433aSKrzysztof Kozlowski adc >>= MAX77693_STATUS1_ADC_SHIFT;
351154f757fSChanwoo Choi
352154f757fSChanwoo Choi /*
353154f757fSChanwoo Choi * Check current cable state/cable type and store cable type
354154f757fSChanwoo Choi * (info->prev_cable_type/_gnd) for handling cable when cable
355154f757fSChanwoo Choi * is detached.
356154f757fSChanwoo Choi */
357154f757fSChanwoo Choi if (adc == MAX77693_MUIC_ADC_OPEN) {
358154f757fSChanwoo Choi *attached = false;
359154f757fSChanwoo Choi
360154f757fSChanwoo Choi cable_type = info->prev_cable_type_gnd;
361154f757fSChanwoo Choi info->prev_cable_type_gnd = MAX77693_MUIC_ADC_OPEN;
362154f757fSChanwoo Choi } else {
363154f757fSChanwoo Choi *attached = true;
364154f757fSChanwoo Choi
365cceb433aSKrzysztof Kozlowski adclow = info->status[0] & MAX77693_STATUS1_ADCLOW_MASK;
366cceb433aSKrzysztof Kozlowski adclow >>= MAX77693_STATUS1_ADCLOW_SHIFT;
367cceb433aSKrzysztof Kozlowski adc1k = info->status[0] & MAX77693_STATUS1_ADC1K_MASK;
368cceb433aSKrzysztof Kozlowski adc1k >>= MAX77693_STATUS1_ADC1K_SHIFT;
369db1b9037SChanwoo Choi
370cceb433aSKrzysztof Kozlowski vbvolt = info->status[1] & MAX77693_STATUS2_VBVOLT_MASK;
371cceb433aSKrzysztof Kozlowski vbvolt >>= MAX77693_STATUS2_VBVOLT_SHIFT;
372154f757fSChanwoo Choi
373db1b9037SChanwoo Choi /**
374c2275d2fSChanwoo Choi * [0x1|VBVolt|ADCLow|ADC1K]
3754c883abeSJaewon Kim * [0x1| 0| 0| 0] USB_HOST
3764c883abeSJaewon Kim * [0x1| 1| 0| 0] USB_HSOT_VB
377c2275d2fSChanwoo Choi * [0x1| 0| 1| 0] Audio Video cable with load
378c2275d2fSChanwoo Choi * [0x1| 0| 1| 1] MHL without charging cable
379c2275d2fSChanwoo Choi * [0x1| 1| 1| 1] MHL with charging cable
380db1b9037SChanwoo Choi */
381154f757fSChanwoo Choi cable_type = ((0x1 << 8)
382154f757fSChanwoo Choi | (vbvolt << 2)
383154f757fSChanwoo Choi | (adclow << 1)
384154f757fSChanwoo Choi | adc1k);
385db1b9037SChanwoo Choi
386154f757fSChanwoo Choi info->prev_cable_type = adc;
387154f757fSChanwoo Choi info->prev_cable_type_gnd = cable_type;
388154f757fSChanwoo Choi }
389db1b9037SChanwoo Choi
390154f757fSChanwoo Choi break;
391154f757fSChanwoo Choi case MAX77693_CABLE_GROUP_CHG:
392154f757fSChanwoo Choi /*
393154f757fSChanwoo Choi * Read charger type to check cable type and decide cable state
394154f757fSChanwoo Choi * according to type of charger cable.
395154f757fSChanwoo Choi */
396cceb433aSKrzysztof Kozlowski chg_type = info->status[1] & MAX77693_STATUS2_CHGTYP_MASK;
397cceb433aSKrzysztof Kozlowski chg_type >>= MAX77693_STATUS2_CHGTYP_SHIFT;
398154f757fSChanwoo Choi
399154f757fSChanwoo Choi if (chg_type == MAX77693_CHARGER_TYPE_NONE) {
400154f757fSChanwoo Choi *attached = false;
401154f757fSChanwoo Choi
402154f757fSChanwoo Choi cable_type = info->prev_chg_type;
403154f757fSChanwoo Choi info->prev_chg_type = MAX77693_CHARGER_TYPE_NONE;
404154f757fSChanwoo Choi } else {
405154f757fSChanwoo Choi *attached = true;
406154f757fSChanwoo Choi
407154f757fSChanwoo Choi /*
408154f757fSChanwoo Choi * Check current cable state/cable type and store cable
409154f757fSChanwoo Choi * type(info->prev_chg_type) for handling cable when
410154f757fSChanwoo Choi * charger cable is detached.
411154f757fSChanwoo Choi */
412154f757fSChanwoo Choi cable_type = info->prev_chg_type = chg_type;
413154f757fSChanwoo Choi }
414154f757fSChanwoo Choi
415154f757fSChanwoo Choi break;
416154f757fSChanwoo Choi case MAX77693_CABLE_GROUP_VBVOLT:
417154f757fSChanwoo Choi /*
418154f757fSChanwoo Choi * Read ADC value to check cable type and decide cable state
419154f757fSChanwoo Choi * according to cable type
420154f757fSChanwoo Choi */
421cceb433aSKrzysztof Kozlowski adc = info->status[0] & MAX77693_STATUS1_ADC_MASK;
422cceb433aSKrzysztof Kozlowski adc >>= MAX77693_STATUS1_ADC_SHIFT;
423cceb433aSKrzysztof Kozlowski chg_type = info->status[1] & MAX77693_STATUS2_CHGTYP_MASK;
424cceb433aSKrzysztof Kozlowski chg_type >>= MAX77693_STATUS2_CHGTYP_SHIFT;
425154f757fSChanwoo Choi
426154f757fSChanwoo Choi if (adc == MAX77693_MUIC_ADC_OPEN
427154f757fSChanwoo Choi && chg_type == MAX77693_CHARGER_TYPE_NONE)
428154f757fSChanwoo Choi *attached = false;
429154f757fSChanwoo Choi else
430154f757fSChanwoo Choi *attached = true;
431154f757fSChanwoo Choi
432154f757fSChanwoo Choi /*
433154f757fSChanwoo Choi * Read vbvolt field, if vbvolt is 1,
434154f757fSChanwoo Choi * this cable is used for charging.
435154f757fSChanwoo Choi */
436cceb433aSKrzysztof Kozlowski vbvolt = info->status[1] & MAX77693_STATUS2_VBVOLT_MASK;
437cceb433aSKrzysztof Kozlowski vbvolt >>= MAX77693_STATUS2_VBVOLT_SHIFT;
438154f757fSChanwoo Choi
439154f757fSChanwoo Choi cable_type = vbvolt;
440154f757fSChanwoo Choi break;
441154f757fSChanwoo Choi default:
442154f757fSChanwoo Choi dev_err(info->dev, "Unknown cable group (%d)\n", group);
443154f757fSChanwoo Choi cable_type = -EINVAL;
444154f757fSChanwoo Choi break;
445154f757fSChanwoo Choi }
446154f757fSChanwoo Choi
447154f757fSChanwoo Choi return cable_type;
448154f757fSChanwoo Choi }
449154f757fSChanwoo Choi
max77693_muic_dock_handler(struct max77693_muic_info * info,int cable_type,bool attached)45039bf369eSChanwoo Choi static int max77693_muic_dock_handler(struct max77693_muic_info *info,
45139bf369eSChanwoo Choi int cable_type, bool attached)
45239bf369eSChanwoo Choi {
45339bf369eSChanwoo Choi int ret = 0;
454a1626298SChanwoo Choi int vbvolt;
455a1626298SChanwoo Choi bool cable_attached;
45673b6ecdbSChanwoo Choi unsigned int dock_id;
45739bf369eSChanwoo Choi
45839bf369eSChanwoo Choi dev_info(info->dev,
45939bf369eSChanwoo Choi "external connector is %s (adc:0x%02x)\n",
46039bf369eSChanwoo Choi attached ? "attached" : "detached", cable_type);
46139bf369eSChanwoo Choi
46239bf369eSChanwoo Choi switch (cable_type) {
46339bf369eSChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
464a1626298SChanwoo Choi /*
465a1626298SChanwoo Choi * Check power cable whether attached or detached state.
466a1626298SChanwoo Choi * The Dock-Smart device need surely external power supply.
467a1626298SChanwoo Choi * If power cable(USB/TA) isn't connected to Dock device,
468a1626298SChanwoo Choi * user can't use Dock-Smart for desktop mode.
469a1626298SChanwoo Choi */
470a1626298SChanwoo Choi vbvolt = max77693_muic_get_cable_type(info,
471a1626298SChanwoo Choi MAX77693_CABLE_GROUP_VBVOLT, &cable_attached);
472a1626298SChanwoo Choi if (attached && !vbvolt) {
473a1626298SChanwoo Choi dev_warn(info->dev,
474a1626298SChanwoo Choi "Cannot detect external power supply\n");
475a1626298SChanwoo Choi return 0;
476a1626298SChanwoo Choi }
47739bf369eSChanwoo Choi
478a1626298SChanwoo Choi /*
479d519c423SChanwoo Choi * Notify Dock/MHL state.
480d519c423SChanwoo Choi * - Dock device include three type of cable which
481a1626298SChanwoo Choi * are HDMI, USB for mouse/keyboard and micro-usb port
482d519c423SChanwoo Choi * for USB/TA cable. Dock device need always exteranl
483d519c423SChanwoo Choi * power supply(USB/TA cable through micro-usb cable). Dock
484d519c423SChanwoo Choi * device support screen output of target to separate
485a1626298SChanwoo Choi * monitor and mouse/keyboard for desktop mode.
486a1626298SChanwoo Choi *
487d519c423SChanwoo Choi * Features of 'USB/TA cable with Dock device'
488a1626298SChanwoo Choi * - Support MHL
489a1626298SChanwoo Choi * - Support external output feature of audio
490a1626298SChanwoo Choi * - Support charging through micro-usb port without data
491a1626298SChanwoo Choi * connection if TA cable is connected to target.
492a1626298SChanwoo Choi * - Support charging and data connection through micro-usb port
493a1626298SChanwoo Choi * if USB cable is connected between target and host
494a1626298SChanwoo Choi * device.
4954c883abeSJaewon Kim * - Support OTG(On-The-Go) device (Ex: Mouse/Keyboard)
496a1626298SChanwoo Choi */
497a1626298SChanwoo Choi ret = max77693_muic_set_path(info, info->path_usb, attached);
498a1626298SChanwoo Choi if (ret < 0)
499a1626298SChanwoo Choi return ret;
500a1626298SChanwoo Choi
5018670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_DOCK, attached);
5028670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached);
50339bf369eSChanwoo Choi goto out;
50439bf369eSChanwoo Choi case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
5052a9de9c0SChanwoo Choi dock_id = EXTCON_DOCK;
50639bf369eSChanwoo Choi break;
50739bf369eSChanwoo Choi case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
5082a9de9c0SChanwoo Choi dock_id = EXTCON_DOCK;
5098b45b6a0SChanwoo Choi if (!attached) {
5108670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_USB, false);
5118670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
5128b45b6a0SChanwoo Choi false);
5138b45b6a0SChanwoo Choi }
51439bf369eSChanwoo Choi break;
51519d3243eSChanwoo Choi default:
51619d3243eSChanwoo Choi dev_err(info->dev, "failed to detect %s dock device\n",
51719d3243eSChanwoo Choi attached ? "attached" : "detached");
51819d3243eSChanwoo Choi return -EINVAL;
51939bf369eSChanwoo Choi }
52039bf369eSChanwoo Choi
52139bf369eSChanwoo Choi /* Dock-Car/Desk/Audio, PATH:AUDIO */
522cceb433aSKrzysztof Kozlowski ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO,
523cceb433aSKrzysztof Kozlowski attached);
52439bf369eSChanwoo Choi if (ret < 0)
525a1626298SChanwoo Choi return ret;
5268670b459SChanwoo Choi extcon_set_state_sync(info->edev, dock_id, attached);
52739bf369eSChanwoo Choi
52839bf369eSChanwoo Choi out:
529a1626298SChanwoo Choi return 0;
53039bf369eSChanwoo Choi }
53139bf369eSChanwoo Choi
max77693_muic_dock_button_handler(struct max77693_muic_info * info,int button_type,bool attached)53239bf369eSChanwoo Choi static int max77693_muic_dock_button_handler(struct max77693_muic_info *info,
53339bf369eSChanwoo Choi int button_type, bool attached)
53439bf369eSChanwoo Choi {
53539bf369eSChanwoo Choi struct input_dev *dock = info->dock;
53639bf369eSChanwoo Choi unsigned int code;
53739bf369eSChanwoo Choi
53839bf369eSChanwoo Choi switch (button_type) {
53939bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON-1
54039bf369eSChanwoo Choi ... MAX77693_MUIC_ADC_REMOTE_S3_BUTTON+1:
54139bf369eSChanwoo Choi /* DOCK_KEY_PREV */
54239bf369eSChanwoo Choi code = KEY_PREVIOUSSONG;
54339bf369eSChanwoo Choi break;
54439bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON-1
54539bf369eSChanwoo Choi ... MAX77693_MUIC_ADC_REMOTE_S7_BUTTON+1:
54639bf369eSChanwoo Choi /* DOCK_KEY_NEXT */
54739bf369eSChanwoo Choi code = KEY_NEXTSONG;
54839bf369eSChanwoo Choi break;
54939bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON:
55039bf369eSChanwoo Choi /* DOCK_VOL_DOWN */
55139bf369eSChanwoo Choi code = KEY_VOLUMEDOWN;
55239bf369eSChanwoo Choi break;
55339bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON:
55439bf369eSChanwoo Choi /* DOCK_VOL_UP */
55539bf369eSChanwoo Choi code = KEY_VOLUMEUP;
55639bf369eSChanwoo Choi break;
55739bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON-1
55839bf369eSChanwoo Choi ... MAX77693_MUIC_ADC_REMOTE_S12_BUTTON+1:
55939bf369eSChanwoo Choi /* DOCK_KEY_PLAY_PAUSE */
56039bf369eSChanwoo Choi code = KEY_PLAYPAUSE;
56139bf369eSChanwoo Choi break;
56239bf369eSChanwoo Choi default:
56339bf369eSChanwoo Choi dev_err(info->dev,
56439bf369eSChanwoo Choi "failed to detect %s key (adc:0x%x)\n",
56539bf369eSChanwoo Choi attached ? "pressed" : "released", button_type);
56619d3243eSChanwoo Choi return -EINVAL;
56739bf369eSChanwoo Choi }
56839bf369eSChanwoo Choi
56939bf369eSChanwoo Choi input_event(dock, EV_KEY, code, attached);
57039bf369eSChanwoo Choi input_sync(dock);
57139bf369eSChanwoo Choi
57239bf369eSChanwoo Choi return 0;
57339bf369eSChanwoo Choi }
57439bf369eSChanwoo Choi
max77693_muic_adc_ground_handler(struct max77693_muic_info * info)575154f757fSChanwoo Choi static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
576154f757fSChanwoo Choi {
577154f757fSChanwoo Choi int cable_type_gnd;
578154f757fSChanwoo Choi int ret = 0;
579154f757fSChanwoo Choi bool attached;
580154f757fSChanwoo Choi
581154f757fSChanwoo Choi cable_type_gnd = max77693_muic_get_cable_type(info,
582154f757fSChanwoo Choi MAX77693_CABLE_GROUP_ADC_GND, &attached);
583154f757fSChanwoo Choi
584154f757fSChanwoo Choi switch (cable_type_gnd) {
5854c883abeSJaewon Kim case MAX77693_MUIC_GND_USB_HOST:
5864c883abeSJaewon Kim case MAX77693_MUIC_GND_USB_HOST_VB:
5874c883abeSJaewon Kim /* USB_HOST, PATH: AP_USB */
588cceb433aSKrzysztof Kozlowski ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_USB,
589cceb433aSKrzysztof Kozlowski attached);
590db1b9037SChanwoo Choi if (ret < 0)
59119d3243eSChanwoo Choi return ret;
5928670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached);
593db1b9037SChanwoo Choi break;
594db1b9037SChanwoo Choi case MAX77693_MUIC_GND_AV_CABLE_LOAD:
59506bed0afSChanwoo Choi /* Audio Video Cable with load, PATH:AUDIO */
596cceb433aSKrzysztof Kozlowski ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO,
597cceb433aSKrzysztof Kozlowski attached);
598db1b9037SChanwoo Choi if (ret < 0)
59919d3243eSChanwoo Choi return ret;
6008670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_USB, attached);
6018670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
6028b45b6a0SChanwoo Choi attached);
603db1b9037SChanwoo Choi break;
60406bed0afSChanwoo Choi case MAX77693_MUIC_GND_MHL:
60506bed0afSChanwoo Choi case MAX77693_MUIC_GND_MHL_VB:
60606bed0afSChanwoo Choi /* MHL or MHL with USB/TA cable */
6078670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached);
608db1b9037SChanwoo Choi break;
609db1b9037SChanwoo Choi default:
61019d3243eSChanwoo Choi dev_err(info->dev, "failed to detect %s cable of gnd type\n",
611db1b9037SChanwoo Choi attached ? "attached" : "detached");
61219d3243eSChanwoo Choi return -EINVAL;
613db1b9037SChanwoo Choi }
614db1b9037SChanwoo Choi
61519d3243eSChanwoo Choi return 0;
616db1b9037SChanwoo Choi }
617db1b9037SChanwoo Choi
max77693_muic_jig_handler(struct max77693_muic_info * info,int cable_type,bool attached)618d0587eb7SChanwoo Choi static int max77693_muic_jig_handler(struct max77693_muic_info *info,
619d0587eb7SChanwoo Choi int cable_type, bool attached)
620d0587eb7SChanwoo Choi {
621d0587eb7SChanwoo Choi int ret = 0;
622cceb433aSKrzysztof Kozlowski u8 path = MAX77693_CONTROL1_SW_OPEN;
623d0587eb7SChanwoo Choi
624d0587eb7SChanwoo Choi dev_info(info->dev,
625d0587eb7SChanwoo Choi "external connector is %s (adc:0x%02x)\n",
626d0587eb7SChanwoo Choi attached ? "attached" : "detached", cable_type);
627d0587eb7SChanwoo Choi
628d0587eb7SChanwoo Choi switch (cable_type) {
629d0587eb7SChanwoo Choi case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
630d0587eb7SChanwoo Choi case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
631d0587eb7SChanwoo Choi /* PATH:AP_USB */
632cceb433aSKrzysztof Kozlowski path = MAX77693_CONTROL1_SW_USB;
633d0587eb7SChanwoo Choi break;
634d0587eb7SChanwoo Choi case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
635c22159a2SKrzysztof Kozlowski case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */
636c22159a2SKrzysztof Kozlowski /* PATH:AP_UART */
637cceb433aSKrzysztof Kozlowski path = MAX77693_CONTROL1_SW_UART;
638c22159a2SKrzysztof Kozlowski break;
63919d3243eSChanwoo Choi default:
64019d3243eSChanwoo Choi dev_err(info->dev, "failed to detect %s jig cable\n",
64119d3243eSChanwoo Choi attached ? "attached" : "detached");
64219d3243eSChanwoo Choi return -EINVAL;
643d0587eb7SChanwoo Choi }
644d0587eb7SChanwoo Choi
645d0587eb7SChanwoo Choi ret = max77693_muic_set_path(info, path, attached);
646d0587eb7SChanwoo Choi if (ret < 0)
64719d3243eSChanwoo Choi return ret;
648d0587eb7SChanwoo Choi
6498670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_JIG, attached);
65019d3243eSChanwoo Choi
65119d3243eSChanwoo Choi return 0;
652d0587eb7SChanwoo Choi }
653d0587eb7SChanwoo Choi
max77693_muic_adc_handler(struct max77693_muic_info * info)654154f757fSChanwoo Choi static int max77693_muic_adc_handler(struct max77693_muic_info *info)
655db1b9037SChanwoo Choi {
656154f757fSChanwoo Choi int cable_type;
65739bf369eSChanwoo Choi int button_type;
658154f757fSChanwoo Choi bool attached;
659db1b9037SChanwoo Choi int ret = 0;
660db1b9037SChanwoo Choi
661154f757fSChanwoo Choi /* Check accessory state which is either detached or attached */
662154f757fSChanwoo Choi cable_type = max77693_muic_get_cable_type(info,
663154f757fSChanwoo Choi MAX77693_CABLE_GROUP_ADC, &attached);
664db1b9037SChanwoo Choi
665db1b9037SChanwoo Choi dev_info(info->dev,
666db1b9037SChanwoo Choi "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
667154f757fSChanwoo Choi attached ? "attached" : "detached", cable_type,
668154f757fSChanwoo Choi info->prev_cable_type);
669db1b9037SChanwoo Choi
670154f757fSChanwoo Choi switch (cable_type) {
671db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_GROUND:
6724c883abeSJaewon Kim /* USB_HOST/MHL/Audio */
673154f757fSChanwoo Choi max77693_muic_adc_ground_handler(info);
674db1b9037SChanwoo Choi break;
675db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF:
676db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON:
677db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF:
678c22159a2SKrzysztof Kozlowski case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON:
679db1b9037SChanwoo Choi /* JIG */
680d0587eb7SChanwoo Choi ret = max77693_muic_jig_handler(info, cable_type, attached);
681db1b9037SChanwoo Choi if (ret < 0)
68219d3243eSChanwoo Choi return ret;
683db1b9037SChanwoo Choi break;
68439bf369eSChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
68539bf369eSChanwoo Choi case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
68639bf369eSChanwoo Choi case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
68739bf369eSChanwoo Choi /*
68839bf369eSChanwoo Choi * DOCK device
68939bf369eSChanwoo Choi *
69039bf369eSChanwoo Choi * The MAX77693 MUIC device can detect total 34 cable type
69139bf369eSChanwoo Choi * except of charger cable and MUIC device didn't define
69239bf369eSChanwoo Choi * specfic role of cable in the range of from 0x01 to 0x12
69339bf369eSChanwoo Choi * of ADC value. So, can use/define cable with no role according
69439bf369eSChanwoo Choi * to schema of hardware board.
69539bf369eSChanwoo Choi */
69639bf369eSChanwoo Choi ret = max77693_muic_dock_handler(info, cable_type, attached);
697db1b9037SChanwoo Choi if (ret < 0)
69819d3243eSChanwoo Choi return ret;
69939bf369eSChanwoo Choi break;
70039bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */
70139bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */
70239bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: /* DOCK_VOL_DOWN */
70339bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: /* DOCK_VOL_UP */
70439bf369eSChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: /* DOCK_KEY_PLAY_PAUSE */
70539bf369eSChanwoo Choi /*
70639bf369eSChanwoo Choi * Button of DOCK device
70739bf369eSChanwoo Choi * - the Prev/Next/Volume Up/Volume Down/Play-Pause button
70839bf369eSChanwoo Choi *
70939bf369eSChanwoo Choi * The MAX77693 MUIC device can detect total 34 cable type
71039bf369eSChanwoo Choi * except of charger cable and MUIC device didn't define
71139bf369eSChanwoo Choi * specfic role of cable in the range of from 0x01 to 0x12
71239bf369eSChanwoo Choi * of ADC value. So, can use/define cable with no role according
71339bf369eSChanwoo Choi * to schema of hardware board.
71439bf369eSChanwoo Choi */
71539bf369eSChanwoo Choi if (attached)
71639bf369eSChanwoo Choi button_type = info->prev_button_type = cable_type;
71739bf369eSChanwoo Choi else
71839bf369eSChanwoo Choi button_type = info->prev_button_type;
71939bf369eSChanwoo Choi
72039bf369eSChanwoo Choi ret = max77693_muic_dock_button_handler(info, button_type,
72139bf369eSChanwoo Choi attached);
72239bf369eSChanwoo Choi if (ret < 0)
72319d3243eSChanwoo Choi return ret;
724db1b9037SChanwoo Choi break;
725db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_SEND_END_BUTTON:
726db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON:
727db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON:
728db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON:
729db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON:
730db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON:
731db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON:
732db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON:
733db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_1:
734db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_2:
735db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_4:
736db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_5:
737db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_CEA936_AUDIO:
738db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_PHONE_POWERED_DEV:
739db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_TTY_CONVERTER:
740db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_UART_CABLE:
741db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG:
742db1b9037SChanwoo Choi case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG:
74339bf369eSChanwoo Choi /*
74439bf369eSChanwoo Choi * This accessory isn't used in general case if it is specially
74539bf369eSChanwoo Choi * needed to detect additional accessory, should implement
74639bf369eSChanwoo Choi * proper operation when this accessory is attached/detached.
74739bf369eSChanwoo Choi */
748db1b9037SChanwoo Choi dev_info(info->dev,
749db1b9037SChanwoo Choi "accessory is %s but it isn't used (adc:0x%x)\n",
750154f757fSChanwoo Choi attached ? "attached" : "detached", cable_type);
75119d3243eSChanwoo Choi return -EAGAIN;
752db1b9037SChanwoo Choi default:
753db1b9037SChanwoo Choi dev_err(info->dev,
754db1b9037SChanwoo Choi "failed to detect %s accessory (adc:0x%x)\n",
755154f757fSChanwoo Choi attached ? "attached" : "detached", cable_type);
75619d3243eSChanwoo Choi return -EINVAL;
757db1b9037SChanwoo Choi }
758db1b9037SChanwoo Choi
75919d3243eSChanwoo Choi return 0;
760db1b9037SChanwoo Choi }
761db1b9037SChanwoo Choi
max77693_muic_chg_handler(struct max77693_muic_info * info)762154f757fSChanwoo Choi static int max77693_muic_chg_handler(struct max77693_muic_info *info)
763db1b9037SChanwoo Choi {
764db1b9037SChanwoo Choi int chg_type;
76506bed0afSChanwoo Choi int cable_type_gnd;
76639bf369eSChanwoo Choi int cable_type;
767154f757fSChanwoo Choi bool attached;
76806bed0afSChanwoo Choi bool cable_attached;
769154f757fSChanwoo Choi int ret = 0;
770db1b9037SChanwoo Choi
771154f757fSChanwoo Choi chg_type = max77693_muic_get_cable_type(info,
772154f757fSChanwoo Choi MAX77693_CABLE_GROUP_CHG, &attached);
773db1b9037SChanwoo Choi
774db1b9037SChanwoo Choi dev_info(info->dev,
775db1b9037SChanwoo Choi "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
776db1b9037SChanwoo Choi attached ? "attached" : "detached",
777154f757fSChanwoo Choi chg_type, info->prev_chg_type);
778db1b9037SChanwoo Choi
779db1b9037SChanwoo Choi switch (chg_type) {
780db1b9037SChanwoo Choi case MAX77693_CHARGER_TYPE_USB:
781a1626298SChanwoo Choi case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
7820e2738f5SChanwoo Choi case MAX77693_CHARGER_TYPE_NONE:
783a1626298SChanwoo Choi /* Check MAX77693_CABLE_GROUP_ADC_GND type */
78406bed0afSChanwoo Choi cable_type_gnd = max77693_muic_get_cable_type(info,
78506bed0afSChanwoo Choi MAX77693_CABLE_GROUP_ADC_GND,
78606bed0afSChanwoo Choi &cable_attached);
787a1626298SChanwoo Choi switch (cable_type_gnd) {
788a1626298SChanwoo Choi case MAX77693_MUIC_GND_MHL:
789a1626298SChanwoo Choi case MAX77693_MUIC_GND_MHL_VB:
790a1626298SChanwoo Choi /*
791942e0239SChanwoo Choi * MHL cable with USB/TA cable
792c2275d2fSChanwoo Choi * - MHL cable include two port(HDMI line and separate
793c2275d2fSChanwoo Choi * micro-usb port. When the target connect MHL cable,
794942e0239SChanwoo Choi * extcon driver check whether USB/TA cable is
795942e0239SChanwoo Choi * connected. If USB/TA cable is connected, extcon
796c2275d2fSChanwoo Choi * driver notify state to notifiee for charging battery.
797a1626298SChanwoo Choi *
798942e0239SChanwoo Choi * Features of 'USB/TA with MHL cable'
799a1626298SChanwoo Choi * - Support MHL
800c2275d2fSChanwoo Choi * - Support charging through micro-usb port without
801c2275d2fSChanwoo Choi * data connection
802a1626298SChanwoo Choi */
8038670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,
80411eecf91SChanwoo Choi attached);
8054243c408SMaciej Purski extcon_set_state_sync(info->edev, EXTCON_DISP_MHL,
8064243c408SMaciej Purski cable_attached);
807a1626298SChanwoo Choi break;
80839bf369eSChanwoo Choi }
80939bf369eSChanwoo Choi
810a1626298SChanwoo Choi /* Check MAX77693_CABLE_GROUP_ADC type */
81139bf369eSChanwoo Choi cable_type = max77693_muic_get_cable_type(info,
81239bf369eSChanwoo Choi MAX77693_CABLE_GROUP_ADC,
81339bf369eSChanwoo Choi &cable_attached);
814a1626298SChanwoo Choi switch (cable_type) {
815a1626298SChanwoo Choi case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
816a1626298SChanwoo Choi /*
817a1626298SChanwoo Choi * Dock-Audio device with USB/TA cable
818c2275d2fSChanwoo Choi * - Dock device include two port(Dock-Audio and micro-
819c2275d2fSChanwoo Choi * usb port). When the target connect Dock-Audio device,
820c2275d2fSChanwoo Choi * extcon driver check whether USB/TA cable is connected
821c2275d2fSChanwoo Choi * or not. If USB/TA cable is connected, extcon driver
822c2275d2fSChanwoo Choi * notify state to notifiee for charging battery.
823a1626298SChanwoo Choi *
824a1626298SChanwoo Choi * Features of 'USB/TA cable with Dock-Audio device'
825a1626298SChanwoo Choi * - Support external output feature of audio.
826c2275d2fSChanwoo Choi * - Support charging through micro-usb port without
827c2275d2fSChanwoo Choi * data connection.
828a1626298SChanwoo Choi */
8298670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_USB,
8302a9de9c0SChanwoo Choi attached);
8318670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
8328b45b6a0SChanwoo Choi attached);
83339bf369eSChanwoo Choi
83439bf369eSChanwoo Choi if (!cable_attached)
8358670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_DOCK,
836c2275d2fSChanwoo Choi cable_attached);
837a1626298SChanwoo Choi break;
838a1626298SChanwoo Choi case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
839a1626298SChanwoo Choi /*
840a1626298SChanwoo Choi * Dock-Smart device with USB/TA cable
841a1626298SChanwoo Choi * - Dock-Desk device include three type of cable which
842a1626298SChanwoo Choi * are HDMI, USB for mouse/keyboard and micro-usb port
843c2275d2fSChanwoo Choi * for USB/TA cable. Dock-Smart device need always
844c2275d2fSChanwoo Choi * exteranl power supply(USB/TA cable through micro-usb
845c2275d2fSChanwoo Choi * cable). Dock-Smart device support screen output of
846c2275d2fSChanwoo Choi * target to separate monitor and mouse/keyboard for
847c2275d2fSChanwoo Choi * desktop mode.
848a1626298SChanwoo Choi *
849a1626298SChanwoo Choi * Features of 'USB/TA cable with Dock-Smart device'
850a1626298SChanwoo Choi * - Support MHL
851a1626298SChanwoo Choi * - Support external output feature of audio
852c2275d2fSChanwoo Choi * - Support charging through micro-usb port without
853c2275d2fSChanwoo Choi * data connection if TA cable is connected to target.
854c2275d2fSChanwoo Choi * - Support charging and data connection through micro-
855c2275d2fSChanwoo Choi * usb port if USB cable is connected between target
856c2275d2fSChanwoo Choi * and host device
8574c883abeSJaewon Kim * - Support OTG(On-The-Go) device (Ex: Mouse/Keyboard)
858a1626298SChanwoo Choi */
859c2275d2fSChanwoo Choi ret = max77693_muic_set_path(info, info->path_usb,
860c2275d2fSChanwoo Choi attached);
861a1626298SChanwoo Choi if (ret < 0)
862a1626298SChanwoo Choi return ret;
863a1626298SChanwoo Choi
8648670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_DOCK,
8652a9de9c0SChanwoo Choi attached);
8668670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_DISP_MHL,
8672a9de9c0SChanwoo Choi attached);
868a1626298SChanwoo Choi break;
86939bf369eSChanwoo Choi }
87039bf369eSChanwoo Choi
871a1626298SChanwoo Choi /* Check MAX77693_CABLE_GROUP_CHG type */
872a1626298SChanwoo Choi switch (chg_type) {
873a1626298SChanwoo Choi case MAX77693_CHARGER_TYPE_NONE:
8740e2738f5SChanwoo Choi /*
875c2275d2fSChanwoo Choi * When MHL(with USB/TA cable) or Dock-Audio with USB/TA
876c2275d2fSChanwoo Choi * cable is attached, muic device happen below two irq.
877c2275d2fSChanwoo Choi * - 'MAX77693_MUIC_IRQ_INT1_ADC' for detecting
878c2275d2fSChanwoo Choi * MHL/Dock-Audio.
879c2275d2fSChanwoo Choi * - 'MAX77693_MUIC_IRQ_INT2_CHGTYP' for detecting
880c2275d2fSChanwoo Choi * USB/TA cable connected to MHL or Dock-Audio.
881c2275d2fSChanwoo Choi * Always, happen eariler MAX77693_MUIC_IRQ_INT1_ADC
882c2275d2fSChanwoo Choi * irq than MAX77693_MUIC_IRQ_INT2_CHGTYP irq.
8830e2738f5SChanwoo Choi *
884c2275d2fSChanwoo Choi * If user attach MHL (with USB/TA cable and immediately
885c2275d2fSChanwoo Choi * detach MHL with USB/TA cable before MAX77693_MUIC_IRQ
886c2275d2fSChanwoo Choi * _INT2_CHGTYP irq is happened, USB/TA cable remain
887c2275d2fSChanwoo Choi * connected state to target. But USB/TA cable isn't
888c2275d2fSChanwoo Choi * connected to target. The user be face with unusual
889c2275d2fSChanwoo Choi * action. So, driver should check this situation in
890c2275d2fSChanwoo Choi * spite of, that previous charger type is N/A.
8910e2738f5SChanwoo Choi */
8920e2738f5SChanwoo Choi break;
893a1626298SChanwoo Choi case MAX77693_CHARGER_TYPE_USB:
89406bed0afSChanwoo Choi /* Only USB cable, PATH:AP_USB */
895c2275d2fSChanwoo Choi ret = max77693_muic_set_path(info, info->path_usb,
896c2275d2fSChanwoo Choi attached);
897db1b9037SChanwoo Choi if (ret < 0)
898a1626298SChanwoo Choi return ret;
899a1626298SChanwoo Choi
9008670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_USB,
9012a9de9c0SChanwoo Choi attached);
9028670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
9038b45b6a0SChanwoo Choi attached);
904db1b9037SChanwoo Choi break;
905a1626298SChanwoo Choi case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
906a1626298SChanwoo Choi /* Only TA cable */
9078670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,
90811eecf91SChanwoo Choi attached);
909a1626298SChanwoo Choi break;
910a1626298SChanwoo Choi }
911a1626298SChanwoo Choi break;
912db1b9037SChanwoo Choi case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
9138670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP,
9142a9de9c0SChanwoo Choi attached);
915db1b9037SChanwoo Choi break;
916db1b9037SChanwoo Choi case MAX77693_CHARGER_TYPE_APPLE_500MA:
9178670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW,
9182a9de9c0SChanwoo Choi attached);
919db1b9037SChanwoo Choi break;
920db1b9037SChanwoo Choi case MAX77693_CHARGER_TYPE_APPLE_1A_2A:
9218670b459SChanwoo Choi extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST,
9222a9de9c0SChanwoo Choi attached);
923db1b9037SChanwoo Choi break;
924db1b9037SChanwoo Choi case MAX77693_CHARGER_TYPE_DEAD_BATTERY:
925db1b9037SChanwoo Choi break;
926db1b9037SChanwoo Choi default:
927db1b9037SChanwoo Choi dev_err(info->dev,
928db1b9037SChanwoo Choi "failed to detect %s accessory (chg_type:0x%x)\n",
929db1b9037SChanwoo Choi attached ? "attached" : "detached", chg_type);
930a1626298SChanwoo Choi return -EINVAL;
931db1b9037SChanwoo Choi }
932db1b9037SChanwoo Choi
933a1626298SChanwoo Choi return 0;
934db1b9037SChanwoo Choi }
935db1b9037SChanwoo Choi
max77693_muic_irq_work(struct work_struct * work)936db1b9037SChanwoo Choi static void max77693_muic_irq_work(struct work_struct *work)
937db1b9037SChanwoo Choi {
938db1b9037SChanwoo Choi struct max77693_muic_info *info = container_of(work,
939db1b9037SChanwoo Choi struct max77693_muic_info, irq_work);
940db1b9037SChanwoo Choi int irq_type = -1;
941db1b9037SChanwoo Choi int i, ret = 0;
942db1b9037SChanwoo Choi
943db1b9037SChanwoo Choi if (!info->edev)
944db1b9037SChanwoo Choi return;
945db1b9037SChanwoo Choi
946db1b9037SChanwoo Choi mutex_lock(&info->mutex);
947db1b9037SChanwoo Choi
948db1b9037SChanwoo Choi for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
949db1b9037SChanwoo Choi if (info->irq == muic_irqs[i].virq)
950db1b9037SChanwoo Choi irq_type = muic_irqs[i].irq;
951db1b9037SChanwoo Choi
952d0540f91SRobert Baldyga ret = regmap_bulk_read(info->max77693->regmap_muic,
953d0540f91SRobert Baldyga MAX77693_MUIC_REG_STATUS1, info->status, 2);
954db1b9037SChanwoo Choi if (ret) {
955db1b9037SChanwoo Choi dev_err(info->dev, "failed to read MUIC register\n");
956db1b9037SChanwoo Choi mutex_unlock(&info->mutex);
957db1b9037SChanwoo Choi return;
958db1b9037SChanwoo Choi }
959db1b9037SChanwoo Choi
960db1b9037SChanwoo Choi switch (irq_type) {
961db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT1_ADC:
962db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT1_ADC_LOW:
963db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT1_ADC_ERR:
964db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT1_ADC1K:
965af57fa4dSSrikant Ritolia /*
966af57fa4dSSrikant Ritolia * Handle all of accessory except for
967af57fa4dSSrikant Ritolia * type of charger accessory.
968af57fa4dSSrikant Ritolia */
969154f757fSChanwoo Choi ret = max77693_muic_adc_handler(info);
970db1b9037SChanwoo Choi break;
971db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT2_CHGTYP:
972db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT2_CHGDETREUN:
973db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT2_DCDTMR:
974db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT2_DXOVP:
975db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT2_VBVOLT:
976db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT2_VIDRM:
977db1b9037SChanwoo Choi /* Handle charger accessory */
978154f757fSChanwoo Choi ret = max77693_muic_chg_handler(info);
979db1b9037SChanwoo Choi break;
980db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT3_EOC:
981db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT3_CGMBC:
982db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT3_OVP:
983db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT3_MBCCHG_ERR:
984db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT3_CHG_ENABLED:
985db1b9037SChanwoo Choi case MAX77693_MUIC_IRQ_INT3_BAT_DET:
986db1b9037SChanwoo Choi break;
987db1b9037SChanwoo Choi default:
988db1b9037SChanwoo Choi dev_err(info->dev, "muic interrupt: irq %d occurred\n",
989db1b9037SChanwoo Choi irq_type);
99019d3243eSChanwoo Choi mutex_unlock(&info->mutex);
99119d3243eSChanwoo Choi return;
992db1b9037SChanwoo Choi }
993db1b9037SChanwoo Choi
994db1b9037SChanwoo Choi if (ret < 0)
995db1b9037SChanwoo Choi dev_err(info->dev, "failed to handle MUIC interrupt\n");
996db1b9037SChanwoo Choi
997db1b9037SChanwoo Choi mutex_unlock(&info->mutex);
998db1b9037SChanwoo Choi }
999db1b9037SChanwoo Choi
max77693_muic_irq_handler(int irq,void * data)1000db1b9037SChanwoo Choi static irqreturn_t max77693_muic_irq_handler(int irq, void *data)
1001db1b9037SChanwoo Choi {
1002db1b9037SChanwoo Choi struct max77693_muic_info *info = data;
1003db1b9037SChanwoo Choi
1004db1b9037SChanwoo Choi info->irq = irq;
1005db1b9037SChanwoo Choi schedule_work(&info->irq_work);
1006db1b9037SChanwoo Choi
1007db1b9037SChanwoo Choi return IRQ_HANDLED;
1008db1b9037SChanwoo Choi }
1009db1b9037SChanwoo Choi
101065948900SKrzysztof Kozlowski static const struct regmap_config max77693_muic_regmap_config = {
1011db1b9037SChanwoo Choi .reg_bits = 8,
1012db1b9037SChanwoo Choi .val_bits = 8,
1013db1b9037SChanwoo Choi };
1014db1b9037SChanwoo Choi
max77693_muic_detect_accessory(struct max77693_muic_info * info)1015db1b9037SChanwoo Choi static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
1016db1b9037SChanwoo Choi {
1017db1b9037SChanwoo Choi int ret = 0;
1018154f757fSChanwoo Choi int adc;
1019154f757fSChanwoo Choi int chg_type;
1020154f757fSChanwoo Choi bool attached;
1021db1b9037SChanwoo Choi
1022db1b9037SChanwoo Choi mutex_lock(&info->mutex);
1023db1b9037SChanwoo Choi
1024db1b9037SChanwoo Choi /* Read STATUSx register to detect accessory */
1025d0540f91SRobert Baldyga ret = regmap_bulk_read(info->max77693->regmap_muic,
1026d0540f91SRobert Baldyga MAX77693_MUIC_REG_STATUS1, info->status, 2);
1027db1b9037SChanwoo Choi if (ret) {
1028db1b9037SChanwoo Choi dev_err(info->dev, "failed to read MUIC register\n");
1029db1b9037SChanwoo Choi mutex_unlock(&info->mutex);
1030c2536543SSachin Kamat return ret;
1031db1b9037SChanwoo Choi }
1032db1b9037SChanwoo Choi
1033154f757fSChanwoo Choi adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC,
1034154f757fSChanwoo Choi &attached);
1035154f757fSChanwoo Choi if (attached && adc != MAX77693_MUIC_ADC_OPEN) {
1036154f757fSChanwoo Choi ret = max77693_muic_adc_handler(info);
103719d3243eSChanwoo Choi if (ret < 0) {
1038154f757fSChanwoo Choi dev_err(info->dev, "Cannot detect accessory\n");
103919d3243eSChanwoo Choi mutex_unlock(&info->mutex);
104019d3243eSChanwoo Choi return ret;
104119d3243eSChanwoo Choi }
1042db1b9037SChanwoo Choi }
1043db1b9037SChanwoo Choi
1044154f757fSChanwoo Choi chg_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_CHG,
1045154f757fSChanwoo Choi &attached);
1046154f757fSChanwoo Choi if (attached && chg_type != MAX77693_CHARGER_TYPE_NONE) {
1047154f757fSChanwoo Choi ret = max77693_muic_chg_handler(info);
104819d3243eSChanwoo Choi if (ret < 0) {
1049154f757fSChanwoo Choi dev_err(info->dev, "Cannot detect charger accessory\n");
105019d3243eSChanwoo Choi mutex_unlock(&info->mutex);
105119d3243eSChanwoo Choi return ret;
105219d3243eSChanwoo Choi }
1053db1b9037SChanwoo Choi }
1054db1b9037SChanwoo Choi
1055db1b9037SChanwoo Choi mutex_unlock(&info->mutex);
1056154f757fSChanwoo Choi
105719d3243eSChanwoo Choi return 0;
1058db1b9037SChanwoo Choi }
1059db1b9037SChanwoo Choi
max77693_muic_detect_cable_wq(struct work_struct * work)1060297620fdSChanwoo Choi static void max77693_muic_detect_cable_wq(struct work_struct *work)
1061297620fdSChanwoo Choi {
1062297620fdSChanwoo Choi struct max77693_muic_info *info = container_of(to_delayed_work(work),
1063297620fdSChanwoo Choi struct max77693_muic_info, wq_detcable);
1064297620fdSChanwoo Choi
1065297620fdSChanwoo Choi max77693_muic_detect_accessory(info);
1066297620fdSChanwoo Choi }
1067297620fdSChanwoo Choi
max77693_muic_probe(struct platform_device * pdev)106844f34fd4SBill Pemberton static int max77693_muic_probe(struct platform_device *pdev)
1069db1b9037SChanwoo Choi {
1070db1b9037SChanwoo Choi struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
1071f8457d57SChanwoo Choi struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
1072db1b9037SChanwoo Choi struct max77693_muic_info *info;
10730ec83bd2SChanwoo Choi struct max77693_reg_data *init_data;
10740ec83bd2SChanwoo Choi int num_init_data;
1075297620fdSChanwoo Choi int delay_jiffies;
10766865f2efSMarek Szyprowski int cable_type;
10776865f2efSMarek Szyprowski bool attached;
1078297620fdSChanwoo Choi int ret;
1079297620fdSChanwoo Choi int i;
1080d0540f91SRobert Baldyga unsigned int id;
1081db1b9037SChanwoo Choi
1082f4bb5cb5SSachin Kamat info = devm_kzalloc(&pdev->dev, sizeof(struct max77693_muic_info),
1083f4bb5cb5SSachin Kamat GFP_KERNEL);
10840a16ee63SJingoo Han if (!info)
1085f4bb5cb5SSachin Kamat return -ENOMEM;
10860a16ee63SJingoo Han
1087db1b9037SChanwoo Choi info->dev = &pdev->dev;
1088db1b9037SChanwoo Choi info->max77693 = max77693;
10891967fa08SSachin Kamat if (info->max77693->regmap_muic) {
1090b186b124SChanwoo Choi dev_dbg(&pdev->dev, "allocate register map\n");
10911967fa08SSachin Kamat } else {
1092b186b124SChanwoo Choi info->max77693->regmap_muic = devm_regmap_init_i2c(
109361b305cdSKrzysztof Kozlowski info->max77693->i2c_muic,
1094db1b9037SChanwoo Choi &max77693_muic_regmap_config);
1095db1b9037SChanwoo Choi if (IS_ERR(info->max77693->regmap_muic)) {
1096db1b9037SChanwoo Choi ret = PTR_ERR(info->max77693->regmap_muic);
1097db1b9037SChanwoo Choi dev_err(max77693->dev,
1098db1b9037SChanwoo Choi "failed to allocate register map: %d\n", ret);
10993bf742ffSSachin Kamat return ret;
1100db1b9037SChanwoo Choi }
1101b186b124SChanwoo Choi }
110239bf369eSChanwoo Choi
110339bf369eSChanwoo Choi /* Register input device for button of dock device */
1104eff7d74fSChanwoo Choi info->dock = devm_input_allocate_device(&pdev->dev);
110539bf369eSChanwoo Choi if (!info->dock) {
110639bf369eSChanwoo Choi dev_err(&pdev->dev, "%s: failed to allocate input\n", __func__);
110739bf369eSChanwoo Choi return -ENOMEM;
110839bf369eSChanwoo Choi }
110939bf369eSChanwoo Choi info->dock->name = "max77693-muic/dock";
111039bf369eSChanwoo Choi info->dock->phys = "max77693-muic/extcon";
111139bf369eSChanwoo Choi info->dock->dev.parent = &pdev->dev;
111239bf369eSChanwoo Choi
111339bf369eSChanwoo Choi __set_bit(EV_REP, info->dock->evbit);
111439bf369eSChanwoo Choi
111539bf369eSChanwoo Choi input_set_capability(info->dock, EV_KEY, KEY_VOLUMEUP);
111639bf369eSChanwoo Choi input_set_capability(info->dock, EV_KEY, KEY_VOLUMEDOWN);
111739bf369eSChanwoo Choi input_set_capability(info->dock, EV_KEY, KEY_PLAYPAUSE);
111839bf369eSChanwoo Choi input_set_capability(info->dock, EV_KEY, KEY_PREVIOUSSONG);
111939bf369eSChanwoo Choi input_set_capability(info->dock, EV_KEY, KEY_NEXTSONG);
112039bf369eSChanwoo Choi
112139bf369eSChanwoo Choi ret = input_register_device(info->dock);
112239bf369eSChanwoo Choi if (ret < 0) {
112339bf369eSChanwoo Choi dev_err(&pdev->dev, "Cannot register input device error(%d)\n",
112439bf369eSChanwoo Choi ret);
112539bf369eSChanwoo Choi return ret;
112639bf369eSChanwoo Choi }
112739bf369eSChanwoo Choi
1128db1b9037SChanwoo Choi platform_set_drvdata(pdev, info);
1129db1b9037SChanwoo Choi mutex_init(&info->mutex);
1130db1b9037SChanwoo Choi
1131*74047eaaSMatti Vaittinen ret = devm_work_autocancel(&pdev->dev, &info->irq_work,
1132*74047eaaSMatti Vaittinen max77693_muic_irq_work);
1133*74047eaaSMatti Vaittinen if (ret)
1134*74047eaaSMatti Vaittinen return ret;
1135db1b9037SChanwoo Choi
1136db1b9037SChanwoo Choi /* Support irq domain for MAX77693 MUIC device */
1137db1b9037SChanwoo Choi for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
1138db1b9037SChanwoo Choi struct max77693_muic_irq *muic_irq = &muic_irqs[i];
1139cbc46603SAndrzej Hajda int virq;
1140db1b9037SChanwoo Choi
1141342d669cSRobert Baldyga virq = regmap_irq_get_virq(max77693->irq_data_muic,
1142342d669cSRobert Baldyga muic_irq->irq);
1143cbc46603SAndrzej Hajda if (virq <= 0)
1144d7155231SKrzysztof Kozlowski return -EINVAL;
1145db1b9037SChanwoo Choi muic_irq->virq = virq;
1146db1b9037SChanwoo Choi
1147d7155231SKrzysztof Kozlowski ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
1148db1b9037SChanwoo Choi max77693_muic_irq_handler,
1149ae3b3215SChanwoo Choi IRQF_NO_SUSPEND,
1150ae3b3215SChanwoo Choi muic_irq->name, info);
1151db1b9037SChanwoo Choi if (ret) {
1152db1b9037SChanwoo Choi dev_err(&pdev->dev,
115334825e51SChanwoo Choi "failed: irq request (IRQ: %d, error :%d)\n",
1154db1b9037SChanwoo Choi muic_irq->irq, ret);
1155d7155231SKrzysztof Kozlowski return ret;
1156db1b9037SChanwoo Choi }
1157db1b9037SChanwoo Choi }
1158db1b9037SChanwoo Choi
1159db1b9037SChanwoo Choi /* Initialize extcon device */
1160577bef11SChanwoo Choi info->edev = devm_extcon_dev_allocate(&pdev->dev,
1161577bef11SChanwoo Choi max77693_extcon_cable);
1162577bef11SChanwoo Choi if (IS_ERR(info->edev)) {
1163db1b9037SChanwoo Choi dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
11641f339f33SKrzysztof Kozlowski return PTR_ERR(info->edev);
1165db1b9037SChanwoo Choi }
1166577bef11SChanwoo Choi
116710fae118SSangjung Woo ret = devm_extcon_dev_register(&pdev->dev, info->edev);
1168db1b9037SChanwoo Choi if (ret) {
1169db1b9037SChanwoo Choi dev_err(&pdev->dev, "failed to register extcon device\n");
1170d7155231SKrzysztof Kozlowski return ret;
1171db1b9037SChanwoo Choi }
1172db1b9037SChanwoo Choi
11730ec83bd2SChanwoo Choi /* Initialize MUIC register by using platform data or default data */
1174d5653f2bSKrzysztof Kozlowski if (pdata && pdata->muic_data) {
11750ec83bd2SChanwoo Choi init_data = pdata->muic_data->init_data;
11760ec83bd2SChanwoo Choi num_init_data = pdata->muic_data->num_init_data;
11770ec83bd2SChanwoo Choi } else {
11780ec83bd2SChanwoo Choi init_data = default_init_data;
11790ec83bd2SChanwoo Choi num_init_data = ARRAY_SIZE(default_init_data);
11800ec83bd2SChanwoo Choi }
11810ec83bd2SChanwoo Choi
11820ec83bd2SChanwoo Choi for (i = 0; i < num_init_data; i++) {
1183d0540f91SRobert Baldyga regmap_write(info->max77693->regmap_muic,
11840ec83bd2SChanwoo Choi init_data[i].addr,
11850ec83bd2SChanwoo Choi init_data[i].data);
1186f8457d57SChanwoo Choi }
1187f8457d57SChanwoo Choi
1188d5653f2bSKrzysztof Kozlowski if (pdata && pdata->muic_data) {
1189c2275d2fSChanwoo Choi struct max77693_muic_platform_data *muic_pdata
1190c2275d2fSChanwoo Choi = pdata->muic_data;
11910ec83bd2SChanwoo Choi
11922b75799fSChanwoo Choi /*
11932b75799fSChanwoo Choi * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
11942b75799fSChanwoo Choi * h/w path of COMP2/COMN1 on CONTROL1 register.
11952b75799fSChanwoo Choi */
11962b75799fSChanwoo Choi if (muic_pdata->path_uart)
11972b75799fSChanwoo Choi info->path_uart = muic_pdata->path_uart;
11982b75799fSChanwoo Choi else
1199cceb433aSKrzysztof Kozlowski info->path_uart = MAX77693_CONTROL1_SW_UART;
12002b75799fSChanwoo Choi
12012b75799fSChanwoo Choi if (muic_pdata->path_usb)
12022b75799fSChanwoo Choi info->path_usb = muic_pdata->path_usb;
12032b75799fSChanwoo Choi else
1204cceb433aSKrzysztof Kozlowski info->path_usb = MAX77693_CONTROL1_SW_USB;
12052b75799fSChanwoo Choi
1206190d7cfcSChanwoo Choi /*
1207190d7cfcSChanwoo Choi * Default delay time for detecting cable state
1208190d7cfcSChanwoo Choi * after certain time.
1209190d7cfcSChanwoo Choi */
1210190d7cfcSChanwoo Choi if (muic_pdata->detcable_delay_ms)
1211190d7cfcSChanwoo Choi delay_jiffies =
1212190d7cfcSChanwoo Choi msecs_to_jiffies(muic_pdata->detcable_delay_ms);
1213190d7cfcSChanwoo Choi else
1214190d7cfcSChanwoo Choi delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
1215190d7cfcSChanwoo Choi } else {
1216cceb433aSKrzysztof Kozlowski info->path_usb = MAX77693_CONTROL1_SW_USB;
1217cceb433aSKrzysztof Kozlowski info->path_uart = MAX77693_CONTROL1_SW_UART;
1218190d7cfcSChanwoo Choi delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
1219190d7cfcSChanwoo Choi }
1220190d7cfcSChanwoo Choi
12216865f2efSMarek Szyprowski /* Set initial path for UART when JIG is connected to get serial logs */
12226865f2efSMarek Szyprowski ret = regmap_bulk_read(info->max77693->regmap_muic,
12236865f2efSMarek Szyprowski MAX77693_MUIC_REG_STATUS1, info->status, 2);
12246865f2efSMarek Szyprowski if (ret) {
12256865f2efSMarek Szyprowski dev_err(info->dev, "failed to read MUIC register\n");
12266865f2efSMarek Szyprowski return ret;
12276865f2efSMarek Szyprowski }
12286865f2efSMarek Szyprowski cable_type = max77693_muic_get_cable_type(info,
12296865f2efSMarek Szyprowski MAX77693_CABLE_GROUP_ADC, &attached);
12306865f2efSMarek Szyprowski if (attached && (cable_type == MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON ||
12316865f2efSMarek Szyprowski cable_type == MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF))
12322b75799fSChanwoo Choi max77693_muic_set_path(info, info->path_uart, true);
12332b75799fSChanwoo Choi
1234db1b9037SChanwoo Choi /* Check revision number of MUIC device*/
1235d0540f91SRobert Baldyga ret = regmap_read(info->max77693->regmap_muic,
1236db1b9037SChanwoo Choi MAX77693_MUIC_REG_ID, &id);
1237db1b9037SChanwoo Choi if (ret < 0) {
1238db1b9037SChanwoo Choi dev_err(&pdev->dev, "failed to read revision number\n");
1239d7155231SKrzysztof Kozlowski return ret;
1240db1b9037SChanwoo Choi }
1241db1b9037SChanwoo Choi dev_info(info->dev, "device ID : 0x%x\n", id);
1242db1b9037SChanwoo Choi
1243db1b9037SChanwoo Choi /* Set ADC debounce time */
1244db1b9037SChanwoo Choi max77693_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
1245db1b9037SChanwoo Choi
1246297620fdSChanwoo Choi /*
1247297620fdSChanwoo Choi * Detect accessory after completing the initialization of platform
1248297620fdSChanwoo Choi *
1249297620fdSChanwoo Choi * - Use delayed workqueue to detect cable state and then
1250297620fdSChanwoo Choi * notify cable state to notifiee/platform through uevent.
1251297620fdSChanwoo Choi * After completing the booting of platform, the extcon provider
1252297620fdSChanwoo Choi * driver should notify cable state to upper layer.
1253297620fdSChanwoo Choi */
1254297620fdSChanwoo Choi INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq);
1255b8629411SKrzysztof Kozlowski queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
1256b8629411SKrzysztof Kozlowski delay_jiffies);
1257db1b9037SChanwoo Choi
1258db1b9037SChanwoo Choi return ret;
1259db1b9037SChanwoo Choi }
1260db1b9037SChanwoo Choi
1261db1b9037SChanwoo Choi static struct platform_driver max77693_muic_driver = {
1262db1b9037SChanwoo Choi .driver = {
1263db1b9037SChanwoo Choi .name = DEV_NAME,
1264db1b9037SChanwoo Choi },
1265db1b9037SChanwoo Choi .probe = max77693_muic_probe,
1266db1b9037SChanwoo Choi };
1267db1b9037SChanwoo Choi
1268db1b9037SChanwoo Choi module_platform_driver(max77693_muic_driver);
1269db1b9037SChanwoo Choi
1270db1b9037SChanwoo Choi MODULE_DESCRIPTION("Maxim MAX77693 Extcon driver");
1271db1b9037SChanwoo Choi MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
1272db1b9037SChanwoo Choi MODULE_LICENSE("GPL");
1273e1efdb60SMarek Szyprowski MODULE_ALIAS("platform:max77693-muic");
1274