1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // extcon-max77843.c - Maxim MAX77843 extcon driver to support
4*4882a593Smuzhiyun // MUIC(Micro USB Interface Controller)
5*4882a593Smuzhiyun //
6*4882a593Smuzhiyun // Copyright (C) 2015 Samsung Electronics
7*4882a593Smuzhiyun // Author: Jaewon Kim <jaewon02.kim@samsung.com>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/extcon-provider.h>
10*4882a593Smuzhiyun #include <linux/i2c.h>
11*4882a593Smuzhiyun #include <linux/interrupt.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/mfd/max77693-common.h>
14*4882a593Smuzhiyun #include <linux/mfd/max77843-private.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/workqueue.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define DELAY_MS_DEFAULT 15000 /* unit: millisecond */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun enum max77843_muic_status {
22*4882a593Smuzhiyun MAX77843_MUIC_STATUS1 = 0,
23*4882a593Smuzhiyun MAX77843_MUIC_STATUS2,
24*4882a593Smuzhiyun MAX77843_MUIC_STATUS3,
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun MAX77843_MUIC_STATUS_NUM,
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct max77843_muic_info {
30*4882a593Smuzhiyun struct device *dev;
31*4882a593Smuzhiyun struct max77693_dev *max77843;
32*4882a593Smuzhiyun struct extcon_dev *edev;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun struct mutex mutex;
35*4882a593Smuzhiyun struct work_struct irq_work;
36*4882a593Smuzhiyun struct delayed_work wq_detcable;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun u8 status[MAX77843_MUIC_STATUS_NUM];
39*4882a593Smuzhiyun int prev_cable_type;
40*4882a593Smuzhiyun int prev_chg_type;
41*4882a593Smuzhiyun int prev_gnd_type;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun bool irq_adc;
44*4882a593Smuzhiyun bool irq_chg;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun enum max77843_muic_cable_group {
48*4882a593Smuzhiyun MAX77843_CABLE_GROUP_ADC = 0,
49*4882a593Smuzhiyun MAX77843_CABLE_GROUP_ADC_GND,
50*4882a593Smuzhiyun MAX77843_CABLE_GROUP_CHG,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun enum max77843_muic_adc_debounce_time {
54*4882a593Smuzhiyun MAX77843_DEBOUNCE_TIME_5MS = 0,
55*4882a593Smuzhiyun MAX77843_DEBOUNCE_TIME_10MS,
56*4882a593Smuzhiyun MAX77843_DEBOUNCE_TIME_25MS,
57*4882a593Smuzhiyun MAX77843_DEBOUNCE_TIME_38_62MS,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* Define accessory cable type */
61*4882a593Smuzhiyun enum max77843_muic_accessory_type {
62*4882a593Smuzhiyun MAX77843_MUIC_ADC_GROUND = 0,
63*4882a593Smuzhiyun MAX77843_MUIC_ADC_SEND_END_BUTTON,
64*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S1_BUTTON,
65*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S2_BUTTON,
66*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S3_BUTTON,
67*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S4_BUTTON,
68*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S5_BUTTON,
69*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S6_BUTTON,
70*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S7_BUTTON,
71*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S8_BUTTON,
72*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S9_BUTTON,
73*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S10_BUTTON,
74*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S11_BUTTON,
75*4882a593Smuzhiyun MAX77843_MUIC_ADC_REMOTE_S12_BUTTON,
76*4882a593Smuzhiyun MAX77843_MUIC_ADC_RESERVED_ACC_1,
77*4882a593Smuzhiyun MAX77843_MUIC_ADC_RESERVED_ACC_2,
78*4882a593Smuzhiyun MAX77843_MUIC_ADC_RESERVED_ACC_3, /* SmartDock */
79*4882a593Smuzhiyun MAX77843_MUIC_ADC_RESERVED_ACC_4,
80*4882a593Smuzhiyun MAX77843_MUIC_ADC_RESERVED_ACC_5,
81*4882a593Smuzhiyun MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2,
82*4882a593Smuzhiyun MAX77843_MUIC_ADC_PHONE_POWERED_DEV,
83*4882a593Smuzhiyun MAX77843_MUIC_ADC_TTY_CONVERTER,
84*4882a593Smuzhiyun MAX77843_MUIC_ADC_UART_CABLE,
85*4882a593Smuzhiyun MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG,
86*4882a593Smuzhiyun MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF,
87*4882a593Smuzhiyun MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON,
88*4882a593Smuzhiyun MAX77843_MUIC_ADC_AV_CABLE_NOLOAD,
89*4882a593Smuzhiyun MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG,
90*4882a593Smuzhiyun MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF,
91*4882a593Smuzhiyun MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON,
92*4882a593Smuzhiyun MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
93*4882a593Smuzhiyun MAX77843_MUIC_ADC_OPEN,
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /*
96*4882a593Smuzhiyun * The below accessories should check
97*4882a593Smuzhiyun * not only ADC value but also ADC1K and VBVolt value.
98*4882a593Smuzhiyun */
99*4882a593Smuzhiyun /* Offset|ADC1K|VBVolt| */
100*4882a593Smuzhiyun MAX77843_MUIC_GND_USB_HOST = 0x100, /* 0x1| 0| 0| */
101*4882a593Smuzhiyun MAX77843_MUIC_GND_USB_HOST_VB = 0x101, /* 0x1| 0| 1| */
102*4882a593Smuzhiyun MAX77843_MUIC_GND_MHL = 0x102, /* 0x1| 1| 0| */
103*4882a593Smuzhiyun MAX77843_MUIC_GND_MHL_VB = 0x103, /* 0x1| 1| 1| */
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* Define charger cable type */
107*4882a593Smuzhiyun enum max77843_muic_charger_type {
108*4882a593Smuzhiyun MAX77843_MUIC_CHG_NONE = 0,
109*4882a593Smuzhiyun MAX77843_MUIC_CHG_USB,
110*4882a593Smuzhiyun MAX77843_MUIC_CHG_DOWNSTREAM,
111*4882a593Smuzhiyun MAX77843_MUIC_CHG_DEDICATED,
112*4882a593Smuzhiyun MAX77843_MUIC_CHG_SPECIAL_500MA,
113*4882a593Smuzhiyun MAX77843_MUIC_CHG_SPECIAL_1A,
114*4882a593Smuzhiyun MAX77843_MUIC_CHG_SPECIAL_BIAS,
115*4882a593Smuzhiyun MAX77843_MUIC_CHG_RESERVED,
116*4882a593Smuzhiyun MAX77843_MUIC_CHG_GND,
117*4882a593Smuzhiyun MAX77843_MUIC_CHG_DOCK,
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun static const unsigned int max77843_extcon_cable[] = {
121*4882a593Smuzhiyun EXTCON_USB,
122*4882a593Smuzhiyun EXTCON_USB_HOST,
123*4882a593Smuzhiyun EXTCON_CHG_USB_SDP,
124*4882a593Smuzhiyun EXTCON_CHG_USB_DCP,
125*4882a593Smuzhiyun EXTCON_CHG_USB_CDP,
126*4882a593Smuzhiyun EXTCON_CHG_USB_FAST,
127*4882a593Smuzhiyun EXTCON_CHG_USB_SLOW,
128*4882a593Smuzhiyun EXTCON_DISP_MHL,
129*4882a593Smuzhiyun EXTCON_DOCK,
130*4882a593Smuzhiyun EXTCON_JIG,
131*4882a593Smuzhiyun EXTCON_NONE,
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun struct max77843_muic_irq {
135*4882a593Smuzhiyun unsigned int irq;
136*4882a593Smuzhiyun const char *name;
137*4882a593Smuzhiyun unsigned int virq;
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun static struct max77843_muic_irq max77843_muic_irqs[] = {
141*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT1_ADC, "MUIC-ADC" },
142*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT1_ADCERROR, "MUIC-ADC_ERROR" },
143*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT1_ADC1K, "MUIC-ADC1K" },
144*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT2_CHGTYP, "MUIC-CHGTYP" },
145*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT2_CHGDETRUN, "MUIC-CHGDETRUN" },
146*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT2_DCDTMR, "MUIC-DCDTMR" },
147*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT2_DXOVP, "MUIC-DXOVP" },
148*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT2_VBVOLT, "MUIC-VBVOLT" },
149*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_VBADC, "MUIC-VBADC" },
150*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_VDNMON, "MUIC-VDNMON" },
151*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_DNRES, "MUIC-DNRES" },
152*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_MPNACK, "MUIC-MPNACK"},
153*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_MRXBUFOW, "MUIC-MRXBUFOW"},
154*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_MRXTRF, "MUIC-MRXTRF"},
155*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_MRXPERR, "MUIC-MRXPERR"},
156*4882a593Smuzhiyun { MAX77843_MUIC_IRQ_INT3_MRXRDY, "MUIC-MRXRDY"},
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun static const struct regmap_config max77843_muic_regmap_config = {
160*4882a593Smuzhiyun .reg_bits = 8,
161*4882a593Smuzhiyun .val_bits = 8,
162*4882a593Smuzhiyun .max_register = MAX77843_MUIC_REG_END,
163*4882a593Smuzhiyun };
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun static const struct regmap_irq max77843_muic_irq[] = {
166*4882a593Smuzhiyun /* INT1 interrupt */
167*4882a593Smuzhiyun { .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
168*4882a593Smuzhiyun { .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
169*4882a593Smuzhiyun { .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* INT2 interrupt */
172*4882a593Smuzhiyun { .reg_offset = 1, .mask = MAX77843_MUIC_CHGTYP, },
173*4882a593Smuzhiyun { .reg_offset = 1, .mask = MAX77843_MUIC_CHGDETRUN, },
174*4882a593Smuzhiyun { .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
175*4882a593Smuzhiyun { .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
176*4882a593Smuzhiyun { .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* INT3 interrupt */
179*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
180*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_VDNMON, },
181*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_DNRES, },
182*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_MPNACK, },
183*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_MRXBUFOW, },
184*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_MRXTRF, },
185*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_MRXPERR, },
186*4882a593Smuzhiyun { .reg_offset = 2, .mask = MAX77843_MUIC_MRXRDY, },
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun static const struct regmap_irq_chip max77843_muic_irq_chip = {
190*4882a593Smuzhiyun .name = "max77843-muic",
191*4882a593Smuzhiyun .status_base = MAX77843_MUIC_REG_INT1,
192*4882a593Smuzhiyun .mask_base = MAX77843_MUIC_REG_INTMASK1,
193*4882a593Smuzhiyun .mask_invert = true,
194*4882a593Smuzhiyun .num_regs = 3,
195*4882a593Smuzhiyun .irqs = max77843_muic_irq,
196*4882a593Smuzhiyun .num_irqs = ARRAY_SIZE(max77843_muic_irq),
197*4882a593Smuzhiyun };
198*4882a593Smuzhiyun
max77843_muic_set_path(struct max77843_muic_info * info,u8 val,bool attached,bool nobccomp)199*4882a593Smuzhiyun static int max77843_muic_set_path(struct max77843_muic_info *info,
200*4882a593Smuzhiyun u8 val, bool attached, bool nobccomp)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun struct max77693_dev *max77843 = info->max77843;
203*4882a593Smuzhiyun int ret = 0;
204*4882a593Smuzhiyun unsigned int ctrl1, ctrl2;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (attached)
207*4882a593Smuzhiyun ctrl1 = val;
208*4882a593Smuzhiyun else
209*4882a593Smuzhiyun ctrl1 = MAX77843_MUIC_CONTROL1_SW_OPEN;
210*4882a593Smuzhiyun if (nobccomp) {
211*4882a593Smuzhiyun /* Disable BC1.2 protocol and force manual switch control */
212*4882a593Smuzhiyun ctrl1 |= MAX77843_MUIC_CONTROL1_NOBCCOMP_MASK;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun ret = regmap_update_bits(max77843->regmap_muic,
216*4882a593Smuzhiyun MAX77843_MUIC_REG_CONTROL1,
217*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_COM_SW |
218*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_NOBCCOMP_MASK,
219*4882a593Smuzhiyun ctrl1);
220*4882a593Smuzhiyun if (ret < 0) {
221*4882a593Smuzhiyun dev_err(info->dev, "Cannot switch MUIC port\n");
222*4882a593Smuzhiyun return ret;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (attached)
226*4882a593Smuzhiyun ctrl2 = MAX77843_MUIC_CONTROL2_CPEN_MASK;
227*4882a593Smuzhiyun else
228*4882a593Smuzhiyun ctrl2 = MAX77843_MUIC_CONTROL2_LOWPWR_MASK;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun ret = regmap_update_bits(max77843->regmap_muic,
231*4882a593Smuzhiyun MAX77843_MUIC_REG_CONTROL2,
232*4882a593Smuzhiyun MAX77843_MUIC_CONTROL2_LOWPWR_MASK |
233*4882a593Smuzhiyun MAX77843_MUIC_CONTROL2_CPEN_MASK, ctrl2);
234*4882a593Smuzhiyun if (ret < 0) {
235*4882a593Smuzhiyun dev_err(info->dev, "Cannot update lowpower mode\n");
236*4882a593Smuzhiyun return ret;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun dev_dbg(info->dev,
240*4882a593Smuzhiyun "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
241*4882a593Smuzhiyun ctrl1, ctrl2, attached ? "attached" : "detached");
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return 0;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
max77843_charger_set_otg_vbus(struct max77843_muic_info * info,bool on)246*4882a593Smuzhiyun static void max77843_charger_set_otg_vbus(struct max77843_muic_info *info,
247*4882a593Smuzhiyun bool on)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun struct max77693_dev *max77843 = info->max77843;
250*4882a593Smuzhiyun unsigned int cnfg00;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (on)
253*4882a593Smuzhiyun cnfg00 = MAX77843_CHG_OTG_MASK | MAX77843_CHG_BOOST_MASK;
254*4882a593Smuzhiyun else
255*4882a593Smuzhiyun cnfg00 = MAX77843_CHG_ENABLE | MAX77843_CHG_BUCK_MASK;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun regmap_update_bits(max77843->regmap_chg, MAX77843_CHG_REG_CHG_CNFG_00,
258*4882a593Smuzhiyun MAX77843_CHG_MODE_MASK, cnfg00);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
max77843_muic_get_cable_type(struct max77843_muic_info * info,enum max77843_muic_cable_group group,bool * attached)261*4882a593Smuzhiyun static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
262*4882a593Smuzhiyun enum max77843_muic_cable_group group, bool *attached)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun int adc, chg_type, cable_type, gnd_type;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun adc = info->status[MAX77843_MUIC_STATUS1] &
267*4882a593Smuzhiyun MAX77843_MUIC_STATUS1_ADC_MASK;
268*4882a593Smuzhiyun adc >>= MAX77843_MUIC_STATUS1_ADC_SHIFT;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun switch (group) {
271*4882a593Smuzhiyun case MAX77843_CABLE_GROUP_ADC:
272*4882a593Smuzhiyun if (adc == MAX77843_MUIC_ADC_OPEN) {
273*4882a593Smuzhiyun *attached = false;
274*4882a593Smuzhiyun cable_type = info->prev_cable_type;
275*4882a593Smuzhiyun info->prev_cable_type = MAX77843_MUIC_ADC_OPEN;
276*4882a593Smuzhiyun } else {
277*4882a593Smuzhiyun *attached = true;
278*4882a593Smuzhiyun cable_type = info->prev_cable_type = adc;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun break;
281*4882a593Smuzhiyun case MAX77843_CABLE_GROUP_CHG:
282*4882a593Smuzhiyun chg_type = info->status[MAX77843_MUIC_STATUS2] &
283*4882a593Smuzhiyun MAX77843_MUIC_STATUS2_CHGTYP_MASK;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* Check GROUND accessory with charger cable */
286*4882a593Smuzhiyun if (adc == MAX77843_MUIC_ADC_GROUND) {
287*4882a593Smuzhiyun if (chg_type == MAX77843_MUIC_CHG_NONE) {
288*4882a593Smuzhiyun /*
289*4882a593Smuzhiyun * The following state when charger cable is
290*4882a593Smuzhiyun * disconnected but the GROUND accessory still
291*4882a593Smuzhiyun * connected.
292*4882a593Smuzhiyun */
293*4882a593Smuzhiyun *attached = false;
294*4882a593Smuzhiyun cable_type = info->prev_chg_type;
295*4882a593Smuzhiyun info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
296*4882a593Smuzhiyun } else {
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /*
299*4882a593Smuzhiyun * The following state when charger cable is
300*4882a593Smuzhiyun * connected on the GROUND accessory.
301*4882a593Smuzhiyun */
302*4882a593Smuzhiyun *attached = true;
303*4882a593Smuzhiyun cable_type = MAX77843_MUIC_CHG_GND;
304*4882a593Smuzhiyun info->prev_chg_type = MAX77843_MUIC_CHG_GND;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun break;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (adc == MAX77843_MUIC_ADC_RESERVED_ACC_3) { /* SmartDock */
310*4882a593Smuzhiyun if (chg_type == MAX77843_MUIC_CHG_NONE) {
311*4882a593Smuzhiyun *attached = false;
312*4882a593Smuzhiyun cable_type = info->prev_chg_type;
313*4882a593Smuzhiyun info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
314*4882a593Smuzhiyun } else {
315*4882a593Smuzhiyun *attached = true;
316*4882a593Smuzhiyun cable_type = MAX77843_MUIC_CHG_DOCK;
317*4882a593Smuzhiyun info->prev_chg_type = MAX77843_MUIC_CHG_DOCK;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun break;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (chg_type == MAX77843_MUIC_CHG_NONE) {
323*4882a593Smuzhiyun *attached = false;
324*4882a593Smuzhiyun cable_type = info->prev_chg_type;
325*4882a593Smuzhiyun info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
326*4882a593Smuzhiyun } else {
327*4882a593Smuzhiyun *attached = true;
328*4882a593Smuzhiyun cable_type = info->prev_chg_type = chg_type;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun break;
331*4882a593Smuzhiyun case MAX77843_CABLE_GROUP_ADC_GND:
332*4882a593Smuzhiyun if (adc == MAX77843_MUIC_ADC_OPEN) {
333*4882a593Smuzhiyun *attached = false;
334*4882a593Smuzhiyun cable_type = info->prev_gnd_type;
335*4882a593Smuzhiyun info->prev_gnd_type = MAX77843_MUIC_ADC_OPEN;
336*4882a593Smuzhiyun } else {
337*4882a593Smuzhiyun *attached = true;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /*
340*4882a593Smuzhiyun * Offset|ADC1K|VBVolt|
341*4882a593Smuzhiyun * 0x1| 0| 0| USB-HOST
342*4882a593Smuzhiyun * 0x1| 0| 1| USB-HOST with VB
343*4882a593Smuzhiyun * 0x1| 1| 0| MHL
344*4882a593Smuzhiyun * 0x1| 1| 1| MHL with VB
345*4882a593Smuzhiyun */
346*4882a593Smuzhiyun /* Get ADC1K register bit */
347*4882a593Smuzhiyun gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
348*4882a593Smuzhiyun MAX77843_MUIC_STATUS1_ADC1K_MASK);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* Get VBVolt register bit */
351*4882a593Smuzhiyun gnd_type |= (info->status[MAX77843_MUIC_STATUS2] &
352*4882a593Smuzhiyun MAX77843_MUIC_STATUS2_VBVOLT_MASK);
353*4882a593Smuzhiyun gnd_type >>= MAX77843_MUIC_STATUS2_VBVOLT_SHIFT;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* Offset of GND cable */
356*4882a593Smuzhiyun gnd_type |= MAX77843_MUIC_GND_USB_HOST;
357*4882a593Smuzhiyun cable_type = info->prev_gnd_type = gnd_type;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun break;
360*4882a593Smuzhiyun default:
361*4882a593Smuzhiyun dev_err(info->dev, "Unknown cable group (%d)\n", group);
362*4882a593Smuzhiyun cable_type = -EINVAL;
363*4882a593Smuzhiyun break;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun return cable_type;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
max77843_muic_adc_gnd_handler(struct max77843_muic_info * info)369*4882a593Smuzhiyun static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun int ret, gnd_cable_type;
372*4882a593Smuzhiyun bool attached;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun gnd_cable_type = max77843_muic_get_cable_type(info,
375*4882a593Smuzhiyun MAX77843_CABLE_GROUP_ADC_GND, &attached);
376*4882a593Smuzhiyun dev_dbg(info->dev, "external connector is %s (gnd:0x%02x)\n",
377*4882a593Smuzhiyun attached ? "attached" : "detached", gnd_cable_type);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun switch (gnd_cable_type) {
380*4882a593Smuzhiyun case MAX77843_MUIC_GND_USB_HOST:
381*4882a593Smuzhiyun case MAX77843_MUIC_GND_USB_HOST_VB:
382*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
383*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_USB,
384*4882a593Smuzhiyun attached, false);
385*4882a593Smuzhiyun if (ret < 0)
386*4882a593Smuzhiyun return ret;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached);
389*4882a593Smuzhiyun max77843_charger_set_otg_vbus(info, attached);
390*4882a593Smuzhiyun break;
391*4882a593Smuzhiyun case MAX77843_MUIC_GND_MHL_VB:
392*4882a593Smuzhiyun case MAX77843_MUIC_GND_MHL:
393*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
394*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_OPEN,
395*4882a593Smuzhiyun attached, false);
396*4882a593Smuzhiyun if (ret < 0)
397*4882a593Smuzhiyun return ret;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached);
400*4882a593Smuzhiyun break;
401*4882a593Smuzhiyun default:
402*4882a593Smuzhiyun dev_err(info->dev, "failed to detect %s accessory(gnd:0x%x)\n",
403*4882a593Smuzhiyun attached ? "attached" : "detached", gnd_cable_type);
404*4882a593Smuzhiyun return -EINVAL;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun return 0;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
max77843_muic_jig_handler(struct max77843_muic_info * info,int cable_type,bool attached)410*4882a593Smuzhiyun static int max77843_muic_jig_handler(struct max77843_muic_info *info,
411*4882a593Smuzhiyun int cable_type, bool attached)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun int ret;
414*4882a593Smuzhiyun u8 path = MAX77843_MUIC_CONTROL1_SW_OPEN;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
417*4882a593Smuzhiyun attached ? "attached" : "detached", cable_type);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun switch (cable_type) {
420*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
421*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
422*4882a593Smuzhiyun path = MAX77843_MUIC_CONTROL1_SW_USB;
423*4882a593Smuzhiyun break;
424*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
425*4882a593Smuzhiyun path = MAX77843_MUIC_CONTROL1_SW_UART;
426*4882a593Smuzhiyun break;
427*4882a593Smuzhiyun default:
428*4882a593Smuzhiyun return -EINVAL;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun ret = max77843_muic_set_path(info, path, attached, false);
432*4882a593Smuzhiyun if (ret < 0)
433*4882a593Smuzhiyun return ret;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_JIG, attached);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun return 0;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
max77843_muic_dock_handler(struct max77843_muic_info * info,bool attached)440*4882a593Smuzhiyun static int max77843_muic_dock_handler(struct max77843_muic_info *info,
441*4882a593Smuzhiyun bool attached)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun int ret;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun dev_dbg(info->dev, "external connector is %s (adc: 0x10)\n",
446*4882a593Smuzhiyun attached ? "attached" : "detached");
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun ret = max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_USB,
449*4882a593Smuzhiyun attached, attached);
450*4882a593Smuzhiyun if (ret < 0)
451*4882a593Smuzhiyun return ret;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached);
454*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached);
455*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_DOCK, attached);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun return 0;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
max77843_muic_adc_handler(struct max77843_muic_info * info)460*4882a593Smuzhiyun static int max77843_muic_adc_handler(struct max77843_muic_info *info)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun int ret, cable_type;
463*4882a593Smuzhiyun bool attached;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun cable_type = max77843_muic_get_cable_type(info,
466*4882a593Smuzhiyun MAX77843_CABLE_GROUP_ADC, &attached);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun dev_dbg(info->dev,
469*4882a593Smuzhiyun "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
470*4882a593Smuzhiyun attached ? "attached" : "detached", cable_type,
471*4882a593Smuzhiyun info->prev_cable_type);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun switch (cable_type) {
474*4882a593Smuzhiyun case MAX77843_MUIC_ADC_RESERVED_ACC_3: /* SmartDock */
475*4882a593Smuzhiyun ret = max77843_muic_dock_handler(info, attached);
476*4882a593Smuzhiyun if (ret < 0)
477*4882a593Smuzhiyun return ret;
478*4882a593Smuzhiyun break;
479*4882a593Smuzhiyun case MAX77843_MUIC_ADC_GROUND:
480*4882a593Smuzhiyun ret = max77843_muic_adc_gnd_handler(info);
481*4882a593Smuzhiyun if (ret < 0)
482*4882a593Smuzhiyun return ret;
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
485*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
486*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
487*4882a593Smuzhiyun ret = max77843_muic_jig_handler(info, cable_type, attached);
488*4882a593Smuzhiyun if (ret < 0)
489*4882a593Smuzhiyun return ret;
490*4882a593Smuzhiyun break;
491*4882a593Smuzhiyun case MAX77843_MUIC_ADC_SEND_END_BUTTON:
492*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S1_BUTTON:
493*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S2_BUTTON:
494*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S3_BUTTON:
495*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S4_BUTTON:
496*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S5_BUTTON:
497*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S6_BUTTON:
498*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S7_BUTTON:
499*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S8_BUTTON:
500*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S9_BUTTON:
501*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S10_BUTTON:
502*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S11_BUTTON:
503*4882a593Smuzhiyun case MAX77843_MUIC_ADC_REMOTE_S12_BUTTON:
504*4882a593Smuzhiyun case MAX77843_MUIC_ADC_RESERVED_ACC_1:
505*4882a593Smuzhiyun case MAX77843_MUIC_ADC_RESERVED_ACC_2:
506*4882a593Smuzhiyun case MAX77843_MUIC_ADC_RESERVED_ACC_4:
507*4882a593Smuzhiyun case MAX77843_MUIC_ADC_RESERVED_ACC_5:
508*4882a593Smuzhiyun case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2:
509*4882a593Smuzhiyun case MAX77843_MUIC_ADC_PHONE_POWERED_DEV:
510*4882a593Smuzhiyun case MAX77843_MUIC_ADC_TTY_CONVERTER:
511*4882a593Smuzhiyun case MAX77843_MUIC_ADC_UART_CABLE:
512*4882a593Smuzhiyun case MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG:
513*4882a593Smuzhiyun case MAX77843_MUIC_ADC_AV_CABLE_NOLOAD:
514*4882a593Smuzhiyun case MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG:
515*4882a593Smuzhiyun case MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON:
516*4882a593Smuzhiyun case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1:
517*4882a593Smuzhiyun case MAX77843_MUIC_ADC_OPEN:
518*4882a593Smuzhiyun dev_err(info->dev,
519*4882a593Smuzhiyun "accessory is %s but it isn't used (adc:0x%x)\n",
520*4882a593Smuzhiyun attached ? "attached" : "detached", cable_type);
521*4882a593Smuzhiyun return -EAGAIN;
522*4882a593Smuzhiyun default:
523*4882a593Smuzhiyun dev_err(info->dev,
524*4882a593Smuzhiyun "failed to detect %s accessory (adc:0x%x)\n",
525*4882a593Smuzhiyun attached ? "attached" : "detached", cable_type);
526*4882a593Smuzhiyun return -EINVAL;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun return 0;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
max77843_muic_chg_handler(struct max77843_muic_info * info)532*4882a593Smuzhiyun static int max77843_muic_chg_handler(struct max77843_muic_info *info)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun int ret, chg_type, gnd_type;
535*4882a593Smuzhiyun bool attached;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun chg_type = max77843_muic_get_cable_type(info,
538*4882a593Smuzhiyun MAX77843_CABLE_GROUP_CHG, &attached);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun dev_dbg(info->dev,
541*4882a593Smuzhiyun "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
542*4882a593Smuzhiyun attached ? "attached" : "detached",
543*4882a593Smuzhiyun chg_type, info->prev_chg_type);
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun switch (chg_type) {
546*4882a593Smuzhiyun case MAX77843_MUIC_CHG_USB:
547*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
548*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_USB,
549*4882a593Smuzhiyun attached, false);
550*4882a593Smuzhiyun if (ret < 0)
551*4882a593Smuzhiyun return ret;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_USB, attached);
554*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
555*4882a593Smuzhiyun attached);
556*4882a593Smuzhiyun break;
557*4882a593Smuzhiyun case MAX77843_MUIC_CHG_DOWNSTREAM:
558*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
559*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_OPEN,
560*4882a593Smuzhiyun attached, false);
561*4882a593Smuzhiyun if (ret < 0)
562*4882a593Smuzhiyun return ret;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP,
565*4882a593Smuzhiyun attached);
566*4882a593Smuzhiyun break;
567*4882a593Smuzhiyun case MAX77843_MUIC_CHG_DEDICATED:
568*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
569*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_OPEN,
570*4882a593Smuzhiyun attached, false);
571*4882a593Smuzhiyun if (ret < 0)
572*4882a593Smuzhiyun return ret;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,
575*4882a593Smuzhiyun attached);
576*4882a593Smuzhiyun break;
577*4882a593Smuzhiyun case MAX77843_MUIC_CHG_SPECIAL_500MA:
578*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
579*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_OPEN,
580*4882a593Smuzhiyun attached, false);
581*4882a593Smuzhiyun if (ret < 0)
582*4882a593Smuzhiyun return ret;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW,
585*4882a593Smuzhiyun attached);
586*4882a593Smuzhiyun break;
587*4882a593Smuzhiyun case MAX77843_MUIC_CHG_SPECIAL_1A:
588*4882a593Smuzhiyun ret = max77843_muic_set_path(info,
589*4882a593Smuzhiyun MAX77843_MUIC_CONTROL1_SW_OPEN,
590*4882a593Smuzhiyun attached, false);
591*4882a593Smuzhiyun if (ret < 0)
592*4882a593Smuzhiyun return ret;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST,
595*4882a593Smuzhiyun attached);
596*4882a593Smuzhiyun break;
597*4882a593Smuzhiyun case MAX77843_MUIC_CHG_GND:
598*4882a593Smuzhiyun gnd_type = max77843_muic_get_cable_type(info,
599*4882a593Smuzhiyun MAX77843_CABLE_GROUP_ADC_GND, &attached);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /* Charger cable on MHL accessory is attach or detach */
602*4882a593Smuzhiyun if (gnd_type == MAX77843_MUIC_GND_MHL_VB)
603*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,
604*4882a593Smuzhiyun true);
605*4882a593Smuzhiyun else if (gnd_type == MAX77843_MUIC_GND_MHL)
606*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,
607*4882a593Smuzhiyun false);
608*4882a593Smuzhiyun break;
609*4882a593Smuzhiyun case MAX77843_MUIC_CHG_DOCK:
610*4882a593Smuzhiyun extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, attached);
611*4882a593Smuzhiyun break;
612*4882a593Smuzhiyun case MAX77843_MUIC_CHG_NONE:
613*4882a593Smuzhiyun break;
614*4882a593Smuzhiyun default:
615*4882a593Smuzhiyun dev_err(info->dev,
616*4882a593Smuzhiyun "failed to detect %s accessory (chg_type:0x%x)\n",
617*4882a593Smuzhiyun attached ? "attached" : "detached", chg_type);
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_OPEN,
620*4882a593Smuzhiyun attached, false);
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun return 0;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
max77843_muic_irq_work(struct work_struct * work)627*4882a593Smuzhiyun static void max77843_muic_irq_work(struct work_struct *work)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun struct max77843_muic_info *info = container_of(work,
630*4882a593Smuzhiyun struct max77843_muic_info, irq_work);
631*4882a593Smuzhiyun struct max77693_dev *max77843 = info->max77843;
632*4882a593Smuzhiyun int ret = 0;
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun mutex_lock(&info->mutex);
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun ret = regmap_bulk_read(max77843->regmap_muic,
637*4882a593Smuzhiyun MAX77843_MUIC_REG_STATUS1, info->status,
638*4882a593Smuzhiyun MAX77843_MUIC_STATUS_NUM);
639*4882a593Smuzhiyun if (ret) {
640*4882a593Smuzhiyun dev_err(info->dev, "Cannot read STATUS registers\n");
641*4882a593Smuzhiyun mutex_unlock(&info->mutex);
642*4882a593Smuzhiyun return;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun if (info->irq_adc) {
646*4882a593Smuzhiyun ret = max77843_muic_adc_handler(info);
647*4882a593Smuzhiyun if (ret)
648*4882a593Smuzhiyun dev_err(info->dev, "Unknown cable type\n");
649*4882a593Smuzhiyun info->irq_adc = false;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun if (info->irq_chg) {
653*4882a593Smuzhiyun ret = max77843_muic_chg_handler(info);
654*4882a593Smuzhiyun if (ret)
655*4882a593Smuzhiyun dev_err(info->dev, "Unknown charger type\n");
656*4882a593Smuzhiyun info->irq_chg = false;
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun mutex_unlock(&info->mutex);
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
max77843_muic_irq_handler(int irq,void * data)662*4882a593Smuzhiyun static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
663*4882a593Smuzhiyun {
664*4882a593Smuzhiyun struct max77843_muic_info *info = data;
665*4882a593Smuzhiyun int i, irq_type = -1;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++)
668*4882a593Smuzhiyun if (irq == max77843_muic_irqs[i].virq)
669*4882a593Smuzhiyun irq_type = max77843_muic_irqs[i].irq;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun switch (irq_type) {
672*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT1_ADC:
673*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT1_ADCERROR:
674*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT1_ADC1K:
675*4882a593Smuzhiyun info->irq_adc = true;
676*4882a593Smuzhiyun break;
677*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT2_CHGTYP:
678*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT2_CHGDETRUN:
679*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT2_DCDTMR:
680*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT2_DXOVP:
681*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT2_VBVOLT:
682*4882a593Smuzhiyun info->irq_chg = true;
683*4882a593Smuzhiyun break;
684*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_VBADC:
685*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_VDNMON:
686*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_DNRES:
687*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_MPNACK:
688*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_MRXBUFOW:
689*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_MRXTRF:
690*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_MRXPERR:
691*4882a593Smuzhiyun case MAX77843_MUIC_IRQ_INT3_MRXRDY:
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun default:
694*4882a593Smuzhiyun dev_err(info->dev, "Cannot recognize IRQ(%d)\n", irq_type);
695*4882a593Smuzhiyun break;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun schedule_work(&info->irq_work);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun return IRQ_HANDLED;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
max77843_muic_detect_cable_wq(struct work_struct * work)703*4882a593Smuzhiyun static void max77843_muic_detect_cable_wq(struct work_struct *work)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun struct max77843_muic_info *info = container_of(to_delayed_work(work),
706*4882a593Smuzhiyun struct max77843_muic_info, wq_detcable);
707*4882a593Smuzhiyun struct max77693_dev *max77843 = info->max77843;
708*4882a593Smuzhiyun int chg_type, adc, ret;
709*4882a593Smuzhiyun bool attached;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun mutex_lock(&info->mutex);
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun ret = regmap_bulk_read(max77843->regmap_muic,
714*4882a593Smuzhiyun MAX77843_MUIC_REG_STATUS1, info->status,
715*4882a593Smuzhiyun MAX77843_MUIC_STATUS_NUM);
716*4882a593Smuzhiyun if (ret) {
717*4882a593Smuzhiyun dev_err(info->dev, "Cannot read STATUS registers\n");
718*4882a593Smuzhiyun goto err_cable_wq;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun adc = max77843_muic_get_cable_type(info,
722*4882a593Smuzhiyun MAX77843_CABLE_GROUP_ADC, &attached);
723*4882a593Smuzhiyun if (attached && adc != MAX77843_MUIC_ADC_OPEN) {
724*4882a593Smuzhiyun ret = max77843_muic_adc_handler(info);
725*4882a593Smuzhiyun if (ret < 0) {
726*4882a593Smuzhiyun dev_err(info->dev, "Cannot detect accessory\n");
727*4882a593Smuzhiyun goto err_cable_wq;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun chg_type = max77843_muic_get_cable_type(info,
732*4882a593Smuzhiyun MAX77843_CABLE_GROUP_CHG, &attached);
733*4882a593Smuzhiyun if (attached && chg_type != MAX77843_MUIC_CHG_NONE) {
734*4882a593Smuzhiyun ret = max77843_muic_chg_handler(info);
735*4882a593Smuzhiyun if (ret < 0) {
736*4882a593Smuzhiyun dev_err(info->dev, "Cannot detect charger accessory\n");
737*4882a593Smuzhiyun goto err_cable_wq;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun err_cable_wq:
742*4882a593Smuzhiyun mutex_unlock(&info->mutex);
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun
max77843_muic_set_debounce_time(struct max77843_muic_info * info,enum max77843_muic_adc_debounce_time time)745*4882a593Smuzhiyun static int max77843_muic_set_debounce_time(struct max77843_muic_info *info,
746*4882a593Smuzhiyun enum max77843_muic_adc_debounce_time time)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun struct max77693_dev *max77843 = info->max77843;
749*4882a593Smuzhiyun int ret;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun switch (time) {
752*4882a593Smuzhiyun case MAX77843_DEBOUNCE_TIME_5MS:
753*4882a593Smuzhiyun case MAX77843_DEBOUNCE_TIME_10MS:
754*4882a593Smuzhiyun case MAX77843_DEBOUNCE_TIME_25MS:
755*4882a593Smuzhiyun case MAX77843_DEBOUNCE_TIME_38_62MS:
756*4882a593Smuzhiyun ret = regmap_update_bits(max77843->regmap_muic,
757*4882a593Smuzhiyun MAX77843_MUIC_REG_CONTROL4,
758*4882a593Smuzhiyun MAX77843_MUIC_CONTROL4_ADCDBSET_MASK,
759*4882a593Smuzhiyun time << MAX77843_MUIC_CONTROL4_ADCDBSET_SHIFT);
760*4882a593Smuzhiyun if (ret < 0) {
761*4882a593Smuzhiyun dev_err(info->dev, "Cannot write MUIC regmap\n");
762*4882a593Smuzhiyun return ret;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun break;
765*4882a593Smuzhiyun default:
766*4882a593Smuzhiyun dev_err(info->dev, "Invalid ADC debounce time\n");
767*4882a593Smuzhiyun return -EINVAL;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun return 0;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun
max77843_init_muic_regmap(struct max77693_dev * max77843)773*4882a593Smuzhiyun static int max77843_init_muic_regmap(struct max77693_dev *max77843)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun int ret;
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun max77843->i2c_muic = i2c_new_dummy_device(max77843->i2c->adapter,
778*4882a593Smuzhiyun I2C_ADDR_MUIC);
779*4882a593Smuzhiyun if (IS_ERR(max77843->i2c_muic)) {
780*4882a593Smuzhiyun dev_err(&max77843->i2c->dev,
781*4882a593Smuzhiyun "Cannot allocate I2C device for MUIC\n");
782*4882a593Smuzhiyun return PTR_ERR(max77843->i2c_muic);
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun i2c_set_clientdata(max77843->i2c_muic, max77843);
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun max77843->regmap_muic = devm_regmap_init_i2c(max77843->i2c_muic,
788*4882a593Smuzhiyun &max77843_muic_regmap_config);
789*4882a593Smuzhiyun if (IS_ERR(max77843->regmap_muic)) {
790*4882a593Smuzhiyun ret = PTR_ERR(max77843->regmap_muic);
791*4882a593Smuzhiyun goto err_muic_i2c;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun ret = regmap_add_irq_chip(max77843->regmap_muic, max77843->irq,
795*4882a593Smuzhiyun IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
796*4882a593Smuzhiyun 0, &max77843_muic_irq_chip, &max77843->irq_data_muic);
797*4882a593Smuzhiyun if (ret < 0) {
798*4882a593Smuzhiyun dev_err(&max77843->i2c->dev, "Cannot add MUIC IRQ chip\n");
799*4882a593Smuzhiyun goto err_muic_i2c;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun return 0;
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun err_muic_i2c:
805*4882a593Smuzhiyun i2c_unregister_device(max77843->i2c_muic);
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun return ret;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
max77843_muic_probe(struct platform_device * pdev)810*4882a593Smuzhiyun static int max77843_muic_probe(struct platform_device *pdev)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent);
813*4882a593Smuzhiyun struct max77843_muic_info *info;
814*4882a593Smuzhiyun unsigned int id;
815*4882a593Smuzhiyun int cable_type;
816*4882a593Smuzhiyun bool attached;
817*4882a593Smuzhiyun int i, ret;
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
820*4882a593Smuzhiyun if (!info)
821*4882a593Smuzhiyun return -ENOMEM;
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun info->dev = &pdev->dev;
824*4882a593Smuzhiyun info->max77843 = max77843;
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun platform_set_drvdata(pdev, info);
827*4882a593Smuzhiyun mutex_init(&info->mutex);
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun /* Initialize i2c and regmap */
830*4882a593Smuzhiyun ret = max77843_init_muic_regmap(max77843);
831*4882a593Smuzhiyun if (ret) {
832*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to init MUIC regmap\n");
833*4882a593Smuzhiyun return ret;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun /* Turn off auto detection configuration */
837*4882a593Smuzhiyun ret = regmap_update_bits(max77843->regmap_muic,
838*4882a593Smuzhiyun MAX77843_MUIC_REG_CONTROL4,
839*4882a593Smuzhiyun MAX77843_MUIC_CONTROL4_USBAUTO_MASK |
840*4882a593Smuzhiyun MAX77843_MUIC_CONTROL4_FCTAUTO_MASK,
841*4882a593Smuzhiyun CONTROL4_AUTO_DISABLE);
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun /* Initialize extcon device */
844*4882a593Smuzhiyun info->edev = devm_extcon_dev_allocate(&pdev->dev,
845*4882a593Smuzhiyun max77843_extcon_cable);
846*4882a593Smuzhiyun if (IS_ERR(info->edev)) {
847*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to allocate memory for extcon\n");
848*4882a593Smuzhiyun ret = PTR_ERR(info->edev);
849*4882a593Smuzhiyun goto err_muic_irq;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun ret = devm_extcon_dev_register(&pdev->dev, info->edev);
853*4882a593Smuzhiyun if (ret) {
854*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to register extcon device\n");
855*4882a593Smuzhiyun goto err_muic_irq;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun /* Set ADC debounce time */
859*4882a593Smuzhiyun max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS);
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun /* Set initial path for UART when JIG is connected to get serial logs */
862*4882a593Smuzhiyun ret = regmap_bulk_read(max77843->regmap_muic,
863*4882a593Smuzhiyun MAX77843_MUIC_REG_STATUS1, info->status,
864*4882a593Smuzhiyun MAX77843_MUIC_STATUS_NUM);
865*4882a593Smuzhiyun if (ret) {
866*4882a593Smuzhiyun dev_err(info->dev, "Cannot read STATUS registers\n");
867*4882a593Smuzhiyun goto err_muic_irq;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun cable_type = max77843_muic_get_cable_type(info, MAX77843_CABLE_GROUP_ADC,
870*4882a593Smuzhiyun &attached);
871*4882a593Smuzhiyun if (attached && cable_type == MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF)
872*4882a593Smuzhiyun max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_UART,
873*4882a593Smuzhiyun true, false);
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun /* Check revision number of MUIC device */
876*4882a593Smuzhiyun ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id);
877*4882a593Smuzhiyun if (ret < 0) {
878*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to read revision number\n");
879*4882a593Smuzhiyun goto err_muic_irq;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun dev_info(info->dev, "MUIC device ID : 0x%x\n", id);
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun /* Support virtual irq domain for max77843 MUIC device */
884*4882a593Smuzhiyun INIT_WORK(&info->irq_work, max77843_muic_irq_work);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun /* Clear IRQ bits before request IRQs */
887*4882a593Smuzhiyun ret = regmap_bulk_read(max77843->regmap_muic,
888*4882a593Smuzhiyun MAX77843_MUIC_REG_INT1, info->status,
889*4882a593Smuzhiyun MAX77843_MUIC_STATUS_NUM);
890*4882a593Smuzhiyun if (ret) {
891*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to Clear IRQ bits\n");
892*4882a593Smuzhiyun goto err_muic_irq;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
896*4882a593Smuzhiyun struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i];
897*4882a593Smuzhiyun int virq = 0;
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun virq = regmap_irq_get_virq(max77843->irq_data_muic,
900*4882a593Smuzhiyun muic_irq->irq);
901*4882a593Smuzhiyun if (virq <= 0) {
902*4882a593Smuzhiyun ret = -EINVAL;
903*4882a593Smuzhiyun goto err_muic_irq;
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun muic_irq->virq = virq;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
908*4882a593Smuzhiyun max77843_muic_irq_handler, IRQF_NO_SUSPEND,
909*4882a593Smuzhiyun muic_irq->name, info);
910*4882a593Smuzhiyun if (ret) {
911*4882a593Smuzhiyun dev_err(&pdev->dev,
912*4882a593Smuzhiyun "Failed to request irq (IRQ: %d, error: %d)\n",
913*4882a593Smuzhiyun muic_irq->irq, ret);
914*4882a593Smuzhiyun goto err_muic_irq;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun /* Detect accessory after completing the initialization of platform */
919*4882a593Smuzhiyun INIT_DELAYED_WORK(&info->wq_detcable, max77843_muic_detect_cable_wq);
920*4882a593Smuzhiyun queue_delayed_work(system_power_efficient_wq,
921*4882a593Smuzhiyun &info->wq_detcable, msecs_to_jiffies(DELAY_MS_DEFAULT));
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun return 0;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun err_muic_irq:
926*4882a593Smuzhiyun regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
927*4882a593Smuzhiyun i2c_unregister_device(max77843->i2c_muic);
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun return ret;
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun
max77843_muic_remove(struct platform_device * pdev)932*4882a593Smuzhiyun static int max77843_muic_remove(struct platform_device *pdev)
933*4882a593Smuzhiyun {
934*4882a593Smuzhiyun struct max77843_muic_info *info = platform_get_drvdata(pdev);
935*4882a593Smuzhiyun struct max77693_dev *max77843 = info->max77843;
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun cancel_work_sync(&info->irq_work);
938*4882a593Smuzhiyun regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
939*4882a593Smuzhiyun i2c_unregister_device(max77843->i2c_muic);
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun return 0;
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun static const struct platform_device_id max77843_muic_id[] = {
945*4882a593Smuzhiyun { "max77843-muic", },
946*4882a593Smuzhiyun { /* sentinel */ },
947*4882a593Smuzhiyun };
948*4882a593Smuzhiyun MODULE_DEVICE_TABLE(platform, max77843_muic_id);
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun static struct platform_driver max77843_muic_driver = {
951*4882a593Smuzhiyun .driver = {
952*4882a593Smuzhiyun .name = "max77843-muic",
953*4882a593Smuzhiyun },
954*4882a593Smuzhiyun .probe = max77843_muic_probe,
955*4882a593Smuzhiyun .remove = max77843_muic_remove,
956*4882a593Smuzhiyun .id_table = max77843_muic_id,
957*4882a593Smuzhiyun };
958*4882a593Smuzhiyun
max77843_muic_init(void)959*4882a593Smuzhiyun static int __init max77843_muic_init(void)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun return platform_driver_register(&max77843_muic_driver);
962*4882a593Smuzhiyun }
963*4882a593Smuzhiyun subsys_initcall(max77843_muic_init);
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun MODULE_DESCRIPTION("Maxim MAX77843 Extcon driver");
966*4882a593Smuzhiyun MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
967*4882a593Smuzhiyun MODULE_LICENSE("GPL");
968