aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon/extcon-rt8973a.c
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2014-08-17 20:05:21 -0400
committerChanwoo Choi <cw00.choi@samsung.com>2014-09-21 22:43:08 -0400
commitc03e017c4d3d0fb783cbe6b7b9e4f278addcb23a (patch)
tree094a1df6e8900089901d13d9d4bb86a2d3892cc4 /drivers/extcon/extcon-rt8973a.c
parentfbae30d8dd35454bd4a55445d1bb51c620f8e646 (diff)
extcon: rt8973a: Add Richtek RT8973A extcon driver
This patch add support for Richtek RT8973A which is Micro USB Switch OVP and i2c interface. The RT8973A is a USB port accessory detector and switch that is optimized to protect low voltage system from abnormal high input voltage (up to 28V) and supports high speed USB operation. Also, RT8973A support 'auto-configuration' mode. If auto-configuration mode is enabled, RT8973A would control internal h/w patch for USB D-/D+ switching. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/extcon/extcon-rt8973a.c')
-rw-r--r--drivers/extcon/extcon-rt8973a.c740
1 files changed, 740 insertions, 0 deletions
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
new file mode 100644
index 000000000000..a784b2d5ee72
--- /dev/null
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -0,0 +1,740 @@
1/*
2 * extcon-rt8973a.c - Richtek RT8973A extcon driver to support USB switches
3 *
4 * Copyright (c) 2014 Samsung Electronics Co., Ltd
5 * Author: Chanwoo Choi <cw00.choi@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/err.h>
14#include <linux/i2c.h>
15#include <linux/input.h>
16#include <linux/interrupt.h>
17#include <linux/irqdomain.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/regmap.h>
22#include <linux/slab.h>
23#include <linux/extcon.h>
24
25#include "extcon-rt8973a.h"
26
27#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
28
29struct muic_irq {
30 unsigned int irq;
31 const char *name;
32 unsigned int virq;
33};
34
35struct reg_data {
36 u8 reg;
37 u8 mask;
38 u8 val;
39 bool invert;
40};
41
42struct rt8973a_muic_info {
43 struct device *dev;
44 struct extcon_dev *edev;
45
46 struct i2c_client *i2c;
47 struct regmap *regmap;
48
49 struct regmap_irq_chip_data *irq_data;
50 struct muic_irq *muic_irqs;
51 unsigned int num_muic_irqs;
52 int irq;
53 bool irq_attach;
54 bool irq_detach;
55 bool irq_ovp;
56 bool irq_otp;
57 struct work_struct irq_work;
58
59 struct reg_data *reg_data;
60 unsigned int num_reg_data;
61 bool auto_config;
62
63 struct mutex mutex;
64
65 /*
66 * Use delayed workqueue to detect cable state and then
67 * notify cable state to notifiee/platform through uevent.
68 * After completing the booting of platform, the extcon provider
69 * driver should notify cable state to upper layer.
70 */
71 struct delayed_work wq_detcable;
72};
73
74/* Default value of RT8973A register to bring up MUIC device. */
75static struct reg_data rt8973a_reg_data[] = {
76 {
77 .reg = RT8973A_REG_CONTROL1,
78 .mask = RT8973A_REG_CONTROL1_ADC_EN_MASK
79 | RT8973A_REG_CONTROL1_USB_CHD_EN_MASK
80 | RT8973A_REG_CONTROL1_CHGTYP_MASK
81 | RT8973A_REG_CONTROL1_SWITCH_OPEN_MASK
82 | RT8973A_REG_CONTROL1_AUTO_CONFIG_MASK
83 | RT8973A_REG_CONTROL1_INTM_MASK,
84 .val = RT8973A_REG_CONTROL1_ADC_EN_MASK
85 | RT8973A_REG_CONTROL1_USB_CHD_EN_MASK
86 | RT8973A_REG_CONTROL1_CHGTYP_MASK,
87 .invert = false,
88 },
89 { /* sentinel */ }
90};
91
92/* List of detectable cables */
93enum {
94 EXTCON_CABLE_USB = 0,
95 EXTCON_CABLE_USB_HOST,
96 EXTCON_CABLE_TA,
97 EXTCON_CABLE_JIG_OFF_USB,
98 EXTCON_CABLE_JIG_ON_USB,
99 EXTCON_CABLE_JIG_OFF_UART,
100 EXTCON_CABLE_JIG_ON_UART,
101
102 EXTCON_CABLE_END,
103};
104
105static const char *rt8973a_extcon_cable[] = {
106 [EXTCON_CABLE_USB] = "USB",
107 [EXTCON_CABLE_USB_HOST] = "USB-Host",
108 [EXTCON_CABLE_TA] = "TA",
109 [EXTCON_CABLE_JIG_OFF_USB] = "JIG-USB-OFF",
110 [EXTCON_CABLE_JIG_ON_USB] = "JIG-USB-ON",
111 [EXTCON_CABLE_JIG_OFF_UART] = "JIG-UART-OFF",
112 [EXTCON_CABLE_JIG_ON_UART] = "JIG-UART-ON",
113 NULL,
114};
115
116/* Define OVP (Over Voltage Protection), OTP (Over Temperature Protection) */
117enum rt8973a_event_type {
118 RT8973A_EVENT_ATTACH = 1,
119 RT8973A_EVENT_DETACH,
120 RT8973A_EVENT_OVP,
121 RT8973A_EVENT_OTP,
122};
123
124/* Define supported accessory type */
125enum rt8973a_muic_acc_type {
126 RT8973A_MUIC_ADC_OTG = 0x0,
127 RT8973A_MUIC_ADC_AUDIO_SEND_END_BUTTON,
128 RT8973A_MUIC_ADC_AUDIO_REMOTE_S1_BUTTON,
129 RT8973A_MUIC_ADC_AUDIO_REMOTE_S2_BUTTON,
130 RT8973A_MUIC_ADC_AUDIO_REMOTE_S3_BUTTON,
131 RT8973A_MUIC_ADC_AUDIO_REMOTE_S4_BUTTON,
132 RT8973A_MUIC_ADC_AUDIO_REMOTE_S5_BUTTON,
133 RT8973A_MUIC_ADC_AUDIO_REMOTE_S6_BUTTON,
134 RT8973A_MUIC_ADC_AUDIO_REMOTE_S7_BUTTON,
135 RT8973A_MUIC_ADC_AUDIO_REMOTE_S8_BUTTON,
136 RT8973A_MUIC_ADC_AUDIO_REMOTE_S9_BUTTON,
137 RT8973A_MUIC_ADC_AUDIO_REMOTE_S10_BUTTON,
138 RT8973A_MUIC_ADC_AUDIO_REMOTE_S11_BUTTON,
139 RT8973A_MUIC_ADC_AUDIO_REMOTE_S12_BUTTON,
140 RT8973A_MUIC_ADC_RESERVED_ACC_1,
141 RT8973A_MUIC_ADC_RESERVED_ACC_2,
142 RT8973A_MUIC_ADC_RESERVED_ACC_3,
143 RT8973A_MUIC_ADC_RESERVED_ACC_4,
144 RT8973A_MUIC_ADC_RESERVED_ACC_5,
145 RT8973A_MUIC_ADC_AUDIO_TYPE2,
146 RT8973A_MUIC_ADC_PHONE_POWERED_DEV,
147 RT8973A_MUIC_ADC_UNKNOWN_ACC_1,
148 RT8973A_MUIC_ADC_UNKNOWN_ACC_2,
149 RT8973A_MUIC_ADC_TA,
150 RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB,
151 RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB,
152 RT8973A_MUIC_ADC_UNKNOWN_ACC_3,
153 RT8973A_MUIC_ADC_UNKNOWN_ACC_4,
154 RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART,
155 RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART,
156 RT8973A_MUIC_ADC_UNKNOWN_ACC_5,
157 RT8973A_MUIC_ADC_OPEN = 0x1f,
158
159 /* The below accessories has same ADC value (0x1f).
160 So, Device type1 is used to separate specific accessory. */
161 /* |---------|--ADC| */
162 /* | [7:5]|[4:0]| */
163 RT8973A_MUIC_ADC_USB = 0x3f, /* | 001|11111| */
164};
165
166/* List of supported interrupt for RT8973A */
167static struct muic_irq rt8973a_muic_irqs[] = {
168 { RT8973A_INT1_ATTACH, "muic-attach" },
169 { RT8973A_INT1_DETACH, "muic-detach" },
170 { RT8973A_INT1_CHGDET, "muic-chgdet" },
171 { RT8973A_INT1_DCD_T, "muic-dcd-t" },
172 { RT8973A_INT1_OVP, "muic-ovp" },
173 { RT8973A_INT1_CONNECT, "muic-connect" },
174 { RT8973A_INT1_ADC_CHG, "muic-adc-chg" },
175 { RT8973A_INT1_OTP, "muic-otp" },
176 { RT8973A_INT2_UVLO, "muic-uvlo" },
177 { RT8973A_INT2_POR, "muic-por" },
178 { RT8973A_INT2_OTP_FET, "muic-otp-fet" },
179 { RT8973A_INT2_OVP_FET, "muic-ovp-fet" },
180 { RT8973A_INT2_OCP_LATCH, "muic-ocp-latch" },
181 { RT8973A_INT2_OCP, "muic-ocp" },
182 { RT8973A_INT2_OVP_OCP, "muic-ovp-ocp" },
183};
184
185/* Define interrupt list of RT8973A to register regmap_irq */
186static const struct regmap_irq rt8973a_irqs[] = {
187 /* INT1 interrupts */
188 { .reg_offset = 0, .mask = RT8973A_INT1_ATTACH_MASK, },
189 { .reg_offset = 0, .mask = RT8973A_INT1_DETACH_MASK, },
190 { .reg_offset = 0, .mask = RT8973A_INT1_CHGDET_MASK, },
191 { .reg_offset = 0, .mask = RT8973A_INT1_DCD_T_MASK, },
192 { .reg_offset = 0, .mask = RT8973A_INT1_OVP_MASK, },
193 { .reg_offset = 0, .mask = RT8973A_INT1_CONNECT_MASK, },
194 { .reg_offset = 0, .mask = RT8973A_INT1_ADC_CHG_MASK, },
195 { .reg_offset = 0, .mask = RT8973A_INT1_OTP_MASK, },
196
197 /* INT2 interrupts */
198 { .reg_offset = 1, .mask = RT8973A_INT2_UVLOT_MASK,},
199 { .reg_offset = 1, .mask = RT8973A_INT2_POR_MASK, },
200 { .reg_offset = 1, .mask = RT8973A_INT2_OTP_FET_MASK, },
201 { .reg_offset = 1, .mask = RT8973A_INT2_OVP_FET_MASK, },
202 { .reg_offset = 1, .mask = RT8973A_INT2_OCP_LATCH_MASK, },
203 { .reg_offset = 1, .mask = RT8973A_INT2_OCP_MASK, },
204 { .reg_offset = 1, .mask = RT8973A_INT2_OVP_OCP_MASK, },
205};
206
207static const struct regmap_irq_chip rt8973a_muic_irq_chip = {
208 .name = "rt8973a",
209 .status_base = RT8973A_REG_INT1,
210 .mask_base = RT8973A_REG_INTM1,
211 .mask_invert = false,
212 .num_regs = 2,
213 .irqs = rt8973a_irqs,
214 .num_irqs = ARRAY_SIZE(rt8973a_irqs),
215};
216
217/* Define regmap configuration of RT8973A for I2C communication */
218static bool rt8973a_muic_volatile_reg(struct device *dev, unsigned int reg)
219{
220 switch (reg) {
221 case RT8973A_REG_INTM1:
222 case RT8973A_REG_INTM2:
223 return true;
224 default:
225 break;
226 }
227 return false;
228}
229
230static const struct regmap_config rt8973a_muic_regmap_config = {
231 .reg_bits = 8,
232 .val_bits = 8,
233 .volatile_reg = rt8973a_muic_volatile_reg,
234 .max_register = RT8973A_REG_END,
235};
236
237/* Change DM_CON/DP_CON/VBUSIN switch according to cable type */
238static int rt8973a_muic_set_path(struct rt8973a_muic_info *info,
239 unsigned int con_sw, bool attached)
240{
241 int ret;
242
243 /*
244 * Don't need to set h/w path according to cable type
245 * if Auto-configuration mode of CONTROL1 register is true.
246 */
247 if (info->auto_config)
248 return 0;
249
250 if (!attached)
251 con_sw = DM_DP_SWITCH_UART;
252
253 switch (con_sw) {
254 case DM_DP_SWITCH_OPEN:
255 case DM_DP_SWITCH_USB:
256 case DM_DP_SWITCH_UART:
257 ret = regmap_update_bits(info->regmap, RT8973A_REG_MANUAL_SW1,
258 RT8973A_REG_MANUAL_SW1_DP_MASK |
259 RT8973A_REG_MANUAL_SW1_DM_MASK,
260 con_sw);
261 if (ret < 0) {
262 dev_err(info->dev,
263 "cannot update DM_CON/DP_CON switch\n");
264 return ret;
265 }
266 break;
267 default:
268 dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
269 con_sw);
270 return -EINVAL;
271 }
272
273 return 0;
274}
275
276static int rt8973a_muic_get_cable_type(struct rt8973a_muic_info *info)
277{
278 unsigned int adc, dev1;
279 int ret, cable_type;
280
281 /* Read ADC value according to external cable or button */
282 ret = regmap_read(info->regmap, RT8973A_REG_ADC, &adc);
283 if (ret) {
284 dev_err(info->dev, "failed to read ADC register\n");
285 return ret;
286 }
287 cable_type = adc & RT8973A_REG_ADC_MASK;
288
289 /* Read Device 1 reigster to identify correct cable type */
290 ret = regmap_read(info->regmap, RT8973A_REG_DEV1, &dev1);
291 if (ret) {
292 dev_err(info->dev, "failed to read DEV1 register\n");
293 return ret;
294 }
295
296 switch (adc) {
297 case RT8973A_MUIC_ADC_OPEN:
298 if (dev1 & RT8973A_REG_DEV1_USB_MASK)
299 cable_type = RT8973A_MUIC_ADC_USB;
300 else if (dev1 & RT8973A_REG_DEV1_DCPORT_MASK)
301 cable_type = RT8973A_MUIC_ADC_TA;
302 else
303 cable_type = RT8973A_MUIC_ADC_OPEN;
304 break;
305 default:
306 break;
307 }
308
309 return cable_type;
310}
311
312static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
313 enum rt8973a_event_type event)
314{
315 static unsigned int prev_cable_type;
316 const char **cable_names = info->edev->supported_cable;
317 unsigned int con_sw = DM_DP_SWITCH_UART;
318 int ret, idx = 0, cable_type;
319 bool attached = false;
320
321 if (!cable_names)
322 return 0;
323
324 switch (event) {
325 case RT8973A_EVENT_ATTACH:
326 cable_type = rt8973a_muic_get_cable_type(info);
327 attached = true;
328 break;
329 case RT8973A_EVENT_DETACH:
330 cable_type = prev_cable_type;
331 attached = false;
332 break;
333 case RT8973A_EVENT_OVP:
334 case RT8973A_EVENT_OTP:
335 dev_warn(info->dev,
336 "happen Over %s issue. Need to disconnect all cables\n",
337 event == RT8973A_EVENT_OVP ? "Voltage" : "Temperature");
338 cable_type = prev_cable_type;
339 attached = false;
340 break;
341 default:
342 dev_err(info->dev,
343 "Cannot handle this event (event:%d)\n", event);
344 return -EINVAL;
345 }
346 prev_cable_type = cable_type;
347
348 switch (cable_type) {
349 case RT8973A_MUIC_ADC_OTG:
350 idx = EXTCON_CABLE_USB_HOST;
351 con_sw = DM_DP_SWITCH_USB;
352 break;
353 case RT8973A_MUIC_ADC_TA:
354 idx = EXTCON_CABLE_TA;
355 con_sw = DM_DP_SWITCH_OPEN;
356 break;
357 case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB:
358 idx = EXTCON_CABLE_JIG_OFF_USB;
359 con_sw = DM_DP_SWITCH_UART;
360 break;
361 case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB:
362 idx = EXTCON_CABLE_JIG_ON_USB;
363 con_sw = DM_DP_SWITCH_UART;
364 break;
365 case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART:
366 idx = EXTCON_CABLE_JIG_OFF_UART;
367 con_sw = DM_DP_SWITCH_UART;
368 break;
369 case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART:
370 idx = EXTCON_CABLE_JIG_ON_UART;
371 con_sw = DM_DP_SWITCH_UART;
372 break;
373 case RT8973A_MUIC_ADC_USB:
374 idx = EXTCON_CABLE_USB;
375 con_sw = DM_DP_SWITCH_USB;
376 break;
377 case RT8973A_MUIC_ADC_OPEN:
378 return 0;
379 case RT8973A_MUIC_ADC_UNKNOWN_ACC_1:
380 case RT8973A_MUIC_ADC_UNKNOWN_ACC_2:
381 case RT8973A_MUIC_ADC_UNKNOWN_ACC_3:
382 case RT8973A_MUIC_ADC_UNKNOWN_ACC_4:
383 case RT8973A_MUIC_ADC_UNKNOWN_ACC_5:
384 dev_warn(info->dev,
385 "Unknown accessory type (adc:0x%x)\n", cable_type);
386 return 0;
387 case RT8973A_MUIC_ADC_AUDIO_SEND_END_BUTTON:
388 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S1_BUTTON:
389 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S2_BUTTON:
390 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S3_BUTTON:
391 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S4_BUTTON:
392 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S5_BUTTON:
393 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S6_BUTTON:
394 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S7_BUTTON:
395 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S8_BUTTON:
396 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S9_BUTTON:
397 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S10_BUTTON:
398 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S11_BUTTON:
399 case RT8973A_MUIC_ADC_AUDIO_REMOTE_S12_BUTTON:
400 case RT8973A_MUIC_ADC_AUDIO_TYPE2:
401 dev_warn(info->dev,
402 "Audio device/button type (adc:0x%x)\n", cable_type);
403 return 0;
404 case RT8973A_MUIC_ADC_RESERVED_ACC_1:
405 case RT8973A_MUIC_ADC_RESERVED_ACC_2:
406 case RT8973A_MUIC_ADC_RESERVED_ACC_3:
407 case RT8973A_MUIC_ADC_RESERVED_ACC_4:
408 case RT8973A_MUIC_ADC_RESERVED_ACC_5:
409 case RT8973A_MUIC_ADC_PHONE_POWERED_DEV:
410 return 0;
411 default:
412 dev_err(info->dev,
413 "Cannot handle this cable_type (adc:0x%x)\n",
414 cable_type);
415 return -EINVAL;
416 }
417
418 /* Change internal hardware path(DM_CON/DP_CON) */
419 ret = rt8973a_muic_set_path(info, con_sw, attached);
420 if (ret < 0)
421 return ret;
422
423 /* Change the state of external accessory */
424 extcon_set_cable_state(info->edev, cable_names[idx], attached);
425
426 return 0;
427}
428
429static void rt8973a_muic_irq_work(struct work_struct *work)
430{
431 struct rt8973a_muic_info *info = container_of(work,
432 struct rt8973a_muic_info, irq_work);
433 int ret = 0;
434
435 if (!info->edev)
436 return;
437
438 mutex_lock(&info->mutex);
439
440 /* Detect attached or detached cables */
441 if (info->irq_attach) {
442 ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_ATTACH);
443 info->irq_attach = false;
444 }
445
446 if (info->irq_detach) {
447 ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_DETACH);
448 info->irq_detach = false;
449 }
450
451 if (info->irq_ovp) {
452 ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_OVP);
453 info->irq_ovp = false;
454 }
455
456 if (info->irq_otp) {
457 ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_OTP);
458 info->irq_otp = false;
459 }
460
461 if (ret < 0)
462 dev_err(info->dev, "failed to handle MUIC interrupt\n");
463
464 mutex_unlock(&info->mutex);
465}
466
467static irqreturn_t rt8973a_muic_irq_handler(int irq, void *data)
468{
469 struct rt8973a_muic_info *info = data;
470 int i, irq_type = -1;
471
472 for (i = 0; i < info->num_muic_irqs; i++)
473 if (irq == info->muic_irqs[i].virq)
474 irq_type = info->muic_irqs[i].irq;
475
476 switch (irq_type) {
477 case RT8973A_INT1_ATTACH:
478 info->irq_attach = true;
479 break;
480 case RT8973A_INT1_DETACH:
481 info->irq_detach = true;
482 break;
483 case RT8973A_INT1_OVP:
484 info->irq_ovp = true;
485 break;
486 case RT8973A_INT1_OTP:
487 info->irq_otp = true;
488 break;
489 case RT8973A_INT1_CHGDET:
490 case RT8973A_INT1_DCD_T:
491 case RT8973A_INT1_CONNECT:
492 case RT8973A_INT1_ADC_CHG:
493 case RT8973A_INT2_UVLO:
494 case RT8973A_INT2_POR:
495 case RT8973A_INT2_OTP_FET:
496 case RT8973A_INT2_OVP_FET:
497 case RT8973A_INT2_OCP_LATCH:
498 case RT8973A_INT2_OCP:
499 case RT8973A_INT2_OVP_OCP:
500 default:
501 dev_dbg(info->dev,
502 "Cannot handle this interrupt (%d)\n", irq_type);
503 break;
504 }
505
506 schedule_work(&info->irq_work);
507
508 return IRQ_HANDLED;
509}
510
511static void rt8973a_muic_detect_cable_wq(struct work_struct *work)
512{
513 struct rt8973a_muic_info *info = container_of(to_delayed_work(work),
514 struct rt8973a_muic_info, wq_detcable);
515 int ret;
516
517 /* Notify the state of connector cable or not */
518 ret = rt8973a_muic_cable_handler(info, RT8973A_EVENT_ATTACH);
519 if (ret < 0)
520 dev_warn(info->dev, "failed to detect cable state\n");
521}
522
523static void rt8973a_init_dev_type(struct rt8973a_muic_info *info)
524{
525 unsigned int data, vendor_id, version_id;
526 int i, ret;
527
528 /* To test I2C, Print version_id and vendor_id of RT8973A */
529 ret = regmap_read(info->regmap, RT8973A_REG_DEVICE_ID, &data);
530 if (ret) {
531 dev_err(info->dev,
532 "failed to read DEVICE_ID register: %d\n", ret);
533 return;
534 }
535
536 vendor_id = ((data & RT8973A_REG_DEVICE_ID_VENDOR_MASK) >>
537 RT8973A_REG_DEVICE_ID_VENDOR_SHIFT);
538 version_id = ((data & RT8973A_REG_DEVICE_ID_VERSION_MASK) >>
539 RT8973A_REG_DEVICE_ID_VERSION_SHIFT);
540
541 dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n",
542 version_id, vendor_id);
543
544 /* Initiazle the register of RT8973A device to bring-up */
545 for (i = 0; i < info->num_reg_data; i++) {
546 u8 reg = info->reg_data[i].reg;
547 u8 mask = info->reg_data[i].mask;
548 u8 val = 0;
549
550 if (info->reg_data[i].invert)
551 val = ~info->reg_data[i].val;
552 else
553 val = info->reg_data[i].val;
554
555 regmap_update_bits(info->regmap, reg, mask, val);
556 }
557
558 /* Check whether RT8973A is auto swithcing mode or not */
559 ret = regmap_read(info->regmap, RT8973A_REG_CONTROL1, &data);
560 if (ret) {
561 dev_err(info->dev,
562 "failed to read CONTROL1 register: %d\n", ret);
563 return;
564 }
565
566 data &= RT8973A_REG_CONTROL1_AUTO_CONFIG_MASK;
567 if (data) {
568 info->auto_config = true;
569 dev_info(info->dev,
570 "Enable Auto-configuration for internal path\n");
571 }
572}
573
574static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
575 const struct i2c_device_id *id)
576{
577 struct device_node *np = i2c->dev.of_node;
578 struct rt8973a_muic_info *info;
579 int i, ret, irq_flags;
580
581 if (!np)
582 return -EINVAL;
583
584 info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
585 if (!info) {
586 dev_err(&i2c->dev, "failed to allocate memory\n");
587 return -ENOMEM;
588 }
589 i2c_set_clientdata(i2c, info);
590
591 info->dev = &i2c->dev;
592 info->i2c = i2c;
593 info->irq = i2c->irq;
594 info->muic_irqs = rt8973a_muic_irqs;
595 info->num_muic_irqs = ARRAY_SIZE(rt8973a_muic_irqs);
596 info->reg_data = rt8973a_reg_data;
597 info->num_reg_data = ARRAY_SIZE(rt8973a_reg_data);
598
599 mutex_init(&info->mutex);
600
601 INIT_WORK(&info->irq_work, rt8973a_muic_irq_work);
602
603 info->regmap = devm_regmap_init_i2c(i2c, &rt8973a_muic_regmap_config);
604 if (IS_ERR(info->regmap)) {
605 ret = PTR_ERR(info->regmap);
606 dev_err(info->dev, "failed to allocate register map: %d\n",
607 ret);
608 return ret;
609 }
610
611 /* Support irq domain for RT8973A MUIC device */
612 irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
613 ret = regmap_add_irq_chip(info->regmap, info->irq, irq_flags, 0,
614 &rt8973a_muic_irq_chip, &info->irq_data);
615 if (ret != 0) {
616 dev_err(info->dev, "failed to add irq_chip (irq:%d, err:%d)\n",
617 info->irq, ret);
618 return ret;
619 }
620
621 for (i = 0; i < info->num_muic_irqs; i++) {
622 struct muic_irq *muic_irq = &info->muic_irqs[i];
623 unsigned int virq = 0;
624
625 virq = regmap_irq_get_virq(info->irq_data, muic_irq->irq);
626 if (virq <= 0)
627 return -EINVAL;
628 muic_irq->virq = virq;
629
630 ret = devm_request_threaded_irq(info->dev, virq, NULL,
631 rt8973a_muic_irq_handler,
632 IRQF_NO_SUSPEND,
633 muic_irq->name, info);
634 if (ret) {
635 dev_err(info->dev,
636 "failed: irq request (IRQ: %d, error :%d)\n",
637 muic_irq->irq, ret);
638 return ret;
639 }
640 }
641
642 /* Allocate extcon device */
643 info->edev = devm_extcon_dev_allocate(info->dev, rt8973a_extcon_cable);
644 if (IS_ERR(info->edev)) {
645 dev_err(info->dev, "failed to allocate memory for extcon\n");
646 return -ENOMEM;
647 }
648 info->edev->name = np->name;
649
650 /* Register extcon device */
651 ret = devm_extcon_dev_register(info->dev, info->edev);
652 if (ret) {
653 dev_err(info->dev, "failed to register extcon device\n");
654 return ret;
655 }
656
657 /*
658 * Detect accessory after completing the initialization of platform
659 *
660 * - Use delayed workqueue to detect cable state and then
661 * notify cable state to notifiee/platform through uevent.
662 * After completing the booting of platform, the extcon provider
663 * driver should notify cable state to upper layer.
664 */
665 INIT_DELAYED_WORK(&info->wq_detcable, rt8973a_muic_detect_cable_wq);
666 queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
667 msecs_to_jiffies(DELAY_MS_DEFAULT));
668
669 /* Initialize RT8973A device and print vendor id and version id */
670 rt8973a_init_dev_type(info);
671
672 return 0;
673}
674
675static int rt8973a_muic_i2c_remove(struct i2c_client *i2c)
676{
677 struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
678
679 regmap_del_irq_chip(info->irq, info->irq_data);
680
681 return 0;
682}
683
684static struct of_device_id rt8973a_dt_match[] = {
685 { .compatible = "richtek,rt8973a-muic" },
686 { },
687};
688
689#ifdef CONFIG_PM_SLEEP
690static int rt8973a_muic_suspend(struct device *dev)
691{
692 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
693 struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
694
695 enable_irq_wake(info->irq);
696
697 return 0;
698}
699
700static int rt8973a_muic_resume(struct device *dev)
701{
702 struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
703 struct rt8973a_muic_info *info = i2c_get_clientdata(i2c);
704
705 disable_irq_wake(info->irq);
706
707 return 0;
708}
709#endif
710
711static SIMPLE_DEV_PM_OPS(rt8973a_muic_pm_ops,
712 rt8973a_muic_suspend, rt8973a_muic_resume);
713
714static const struct i2c_device_id rt8973a_i2c_id[] = {
715 { "rt8973a", TYPE_RT8973A },
716 { }
717};
718MODULE_DEVICE_TABLE(i2c, rt8973a_i2c_id);
719
720static struct i2c_driver rt8973a_muic_i2c_driver = {
721 .driver = {
722 .name = "rt8973a",
723 .owner = THIS_MODULE,
724 .pm = &rt8973a_muic_pm_ops,
725 .of_match_table = rt8973a_dt_match,
726 },
727 .probe = rt8973a_muic_i2c_probe,
728 .remove = rt8973a_muic_i2c_remove,
729 .id_table = rt8973a_i2c_id,
730};
731
732static int __init rt8973a_muic_i2c_init(void)
733{
734 return i2c_add_driver(&rt8973a_muic_i2c_driver);
735}
736subsys_initcall(rt8973a_muic_i2c_init);
737
738MODULE_DESCRIPTION("Richtek RT8973A Extcon driver");
739MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
740MODULE_LICENSE("GPL");