extcon-sm5502.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * extcon-sm5502.c - Silicon Mitus SM5502 extcon drvier to support USB switches
  4. *
  5. * Copyright (c) 2014 Samsung Electronics Co., Ltd
  6. * Author: Chanwoo Choi <[email protected]>
  7. */
  8. #include <linux/err.h>
  9. #include <linux/i2c.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/irqdomain.h>
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/regmap.h>
  16. #include <linux/slab.h>
  17. #include <linux/extcon-provider.h>
  18. #include "extcon-sm5502.h"
  19. #define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
  20. struct muic_irq {
  21. unsigned int irq;
  22. const char *name;
  23. unsigned int virq;
  24. };
  25. struct reg_data {
  26. u8 reg;
  27. unsigned int val;
  28. bool invert;
  29. };
  30. struct sm5502_muic_info {
  31. struct device *dev;
  32. struct extcon_dev *edev;
  33. struct i2c_client *i2c;
  34. struct regmap *regmap;
  35. const struct sm5502_type *type;
  36. struct regmap_irq_chip_data *irq_data;
  37. int irq;
  38. bool irq_attach;
  39. bool irq_detach;
  40. struct work_struct irq_work;
  41. struct mutex mutex;
  42. /*
  43. * Use delayed workqueue to detect cable state and then
  44. * notify cable state to notifiee/platform through uevent.
  45. * After completing the booting of platform, the extcon provider
  46. * driver should notify cable state to upper layer.
  47. */
  48. struct delayed_work wq_detcable;
  49. };
  50. struct sm5502_type {
  51. struct muic_irq *muic_irqs;
  52. unsigned int num_muic_irqs;
  53. const struct regmap_irq_chip *irq_chip;
  54. struct reg_data *reg_data;
  55. unsigned int num_reg_data;
  56. unsigned int otg_dev_type1;
  57. int (*parse_irq)(struct sm5502_muic_info *info, int irq_type);
  58. };
  59. /* Default value of SM5502 register to bring up MUIC device. */
  60. static struct reg_data sm5502_reg_data[] = {
  61. {
  62. .reg = SM5502_REG_RESET,
  63. .val = SM5502_REG_RESET_MASK,
  64. .invert = true,
  65. }, {
  66. .reg = SM5502_REG_CONTROL,
  67. .val = SM5502_REG_CONTROL_MASK_INT_MASK,
  68. .invert = false,
  69. }, {
  70. .reg = SM5502_REG_INTMASK1,
  71. .val = SM5502_REG_INTM1_KP_MASK
  72. | SM5502_REG_INTM1_LKP_MASK
  73. | SM5502_REG_INTM1_LKR_MASK,
  74. .invert = true,
  75. }, {
  76. .reg = SM5502_REG_INTMASK2,
  77. .val = SM5502_REG_INTM2_VBUS_DET_MASK
  78. | SM5502_REG_INTM2_REV_ACCE_MASK
  79. | SM5502_REG_INTM2_ADC_CHG_MASK
  80. | SM5502_REG_INTM2_STUCK_KEY_MASK
  81. | SM5502_REG_INTM2_STUCK_KEY_RCV_MASK
  82. | SM5502_REG_INTM2_MHL_MASK,
  83. .invert = true,
  84. },
  85. };
  86. /* Default value of SM5504 register to bring up MUIC device. */
  87. static struct reg_data sm5504_reg_data[] = {
  88. {
  89. .reg = SM5502_REG_RESET,
  90. .val = SM5502_REG_RESET_MASK,
  91. .invert = true,
  92. }, {
  93. .reg = SM5502_REG_INTMASK1,
  94. .val = SM5504_REG_INTM1_ATTACH_MASK
  95. | SM5504_REG_INTM1_DETACH_MASK,
  96. .invert = false,
  97. }, {
  98. .reg = SM5502_REG_INTMASK2,
  99. .val = SM5504_REG_INTM2_RID_CHG_MASK
  100. | SM5504_REG_INTM2_UVLO_MASK
  101. | SM5504_REG_INTM2_POR_MASK,
  102. .invert = true,
  103. }, {
  104. .reg = SM5502_REG_CONTROL,
  105. .val = SM5502_REG_CONTROL_MANUAL_SW_MASK
  106. | SM5504_REG_CONTROL_CHGTYP_MASK
  107. | SM5504_REG_CONTROL_USBCHDEN_MASK
  108. | SM5504_REG_CONTROL_ADC_EN_MASK,
  109. .invert = true,
  110. },
  111. };
  112. /* List of detectable cables */
  113. static const unsigned int sm5502_extcon_cable[] = {
  114. EXTCON_USB,
  115. EXTCON_USB_HOST,
  116. EXTCON_CHG_USB_SDP,
  117. EXTCON_CHG_USB_DCP,
  118. EXTCON_NONE,
  119. };
  120. /* Define supported accessory type */
  121. enum sm5502_muic_acc_type {
  122. SM5502_MUIC_ADC_GROUND = 0x0,
  123. SM5502_MUIC_ADC_SEND_END_BUTTON,
  124. SM5502_MUIC_ADC_REMOTE_S1_BUTTON,
  125. SM5502_MUIC_ADC_REMOTE_S2_BUTTON,
  126. SM5502_MUIC_ADC_REMOTE_S3_BUTTON,
  127. SM5502_MUIC_ADC_REMOTE_S4_BUTTON,
  128. SM5502_MUIC_ADC_REMOTE_S5_BUTTON,
  129. SM5502_MUIC_ADC_REMOTE_S6_BUTTON,
  130. SM5502_MUIC_ADC_REMOTE_S7_BUTTON,
  131. SM5502_MUIC_ADC_REMOTE_S8_BUTTON,
  132. SM5502_MUIC_ADC_REMOTE_S9_BUTTON,
  133. SM5502_MUIC_ADC_REMOTE_S10_BUTTON,
  134. SM5502_MUIC_ADC_REMOTE_S11_BUTTON,
  135. SM5502_MUIC_ADC_REMOTE_S12_BUTTON,
  136. SM5502_MUIC_ADC_RESERVED_ACC_1,
  137. SM5502_MUIC_ADC_RESERVED_ACC_2,
  138. SM5502_MUIC_ADC_RESERVED_ACC_3,
  139. SM5502_MUIC_ADC_RESERVED_ACC_4,
  140. SM5502_MUIC_ADC_RESERVED_ACC_5,
  141. SM5502_MUIC_ADC_AUDIO_TYPE2,
  142. SM5502_MUIC_ADC_PHONE_POWERED_DEV,
  143. SM5502_MUIC_ADC_TTY_CONVERTER,
  144. SM5502_MUIC_ADC_UART_CABLE,
  145. SM5502_MUIC_ADC_TYPE1_CHARGER,
  146. SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB,
  147. SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB,
  148. SM5502_MUIC_ADC_AUDIO_VIDEO_CABLE,
  149. SM5502_MUIC_ADC_TYPE2_CHARGER,
  150. SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART,
  151. SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART,
  152. SM5502_MUIC_ADC_AUDIO_TYPE1,
  153. SM5502_MUIC_ADC_OPEN = 0x1f,
  154. /*
  155. * The below accessories have same ADC value (0x1f or 0x1e).
  156. * So, Device type1 is used to separate specific accessory.
  157. */
  158. /* |---------|--ADC| */
  159. /* | [7:5]|[4:0]| */
  160. SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* | 001|11110| */
  161. SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END = 0x5e, /* | 010|11110| */
  162. /* |Dev Type1|--ADC| */
  163. SM5502_MUIC_ADC_GROUND_USB_OTG = 0x80, /* | 100|00000| */
  164. SM5502_MUIC_ADC_OPEN_USB = 0x5f, /* | 010|11111| */
  165. SM5502_MUIC_ADC_OPEN_TA = 0xdf, /* | 110|11111| */
  166. SM5502_MUIC_ADC_OPEN_USB_OTG = 0xff, /* | 111|11111| */
  167. };
  168. /* List of supported interrupt for SM5502 */
  169. static struct muic_irq sm5502_muic_irqs[] = {
  170. { SM5502_IRQ_INT1_ATTACH, "muic-attach" },
  171. { SM5502_IRQ_INT1_DETACH, "muic-detach" },
  172. { SM5502_IRQ_INT1_KP, "muic-kp" },
  173. { SM5502_IRQ_INT1_LKP, "muic-lkp" },
  174. { SM5502_IRQ_INT1_LKR, "muic-lkr" },
  175. { SM5502_IRQ_INT1_OVP_EVENT, "muic-ovp-event" },
  176. { SM5502_IRQ_INT1_OCP_EVENT, "muic-ocp-event" },
  177. { SM5502_IRQ_INT1_OVP_OCP_DIS, "muic-ovp-ocp-dis" },
  178. { SM5502_IRQ_INT2_VBUS_DET, "muic-vbus-det" },
  179. { SM5502_IRQ_INT2_REV_ACCE, "muic-rev-acce" },
  180. { SM5502_IRQ_INT2_ADC_CHG, "muic-adc-chg" },
  181. { SM5502_IRQ_INT2_STUCK_KEY, "muic-stuck-key" },
  182. { SM5502_IRQ_INT2_STUCK_KEY_RCV, "muic-stuck-key-rcv" },
  183. { SM5502_IRQ_INT2_MHL, "muic-mhl" },
  184. };
  185. /* Define interrupt list of SM5502 to register regmap_irq */
  186. static const struct regmap_irq sm5502_irqs[] = {
  187. /* INT1 interrupts */
  188. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_ATTACH_MASK, },
  189. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_DETACH_MASK, },
  190. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_KP_MASK, },
  191. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_LKP_MASK, },
  192. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_LKR_MASK, },
  193. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OVP_EVENT_MASK, },
  194. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OCP_EVENT_MASK, },
  195. { .reg_offset = 0, .mask = SM5502_IRQ_INT1_OVP_OCP_DIS_MASK, },
  196. /* INT2 interrupts */
  197. { .reg_offset = 1, .mask = SM5502_IRQ_INT2_VBUS_DET_MASK,},
  198. { .reg_offset = 1, .mask = SM5502_IRQ_INT2_REV_ACCE_MASK, },
  199. { .reg_offset = 1, .mask = SM5502_IRQ_INT2_ADC_CHG_MASK, },
  200. { .reg_offset = 1, .mask = SM5502_IRQ_INT2_STUCK_KEY_MASK, },
  201. { .reg_offset = 1, .mask = SM5502_IRQ_INT2_STUCK_KEY_RCV_MASK, },
  202. { .reg_offset = 1, .mask = SM5502_IRQ_INT2_MHL_MASK, },
  203. };
  204. static const struct regmap_irq_chip sm5502_muic_irq_chip = {
  205. .name = "sm5502",
  206. .status_base = SM5502_REG_INT1,
  207. .mask_base = SM5502_REG_INTMASK1,
  208. .num_regs = 2,
  209. .irqs = sm5502_irqs,
  210. .num_irqs = ARRAY_SIZE(sm5502_irqs),
  211. };
  212. /* List of supported interrupt for SM5504 */
  213. static struct muic_irq sm5504_muic_irqs[] = {
  214. { SM5504_IRQ_INT1_ATTACH, "muic-attach" },
  215. { SM5504_IRQ_INT1_DETACH, "muic-detach" },
  216. { SM5504_IRQ_INT1_CHG_DET, "muic-chg-det" },
  217. { SM5504_IRQ_INT1_DCD_OUT, "muic-dcd-out" },
  218. { SM5504_IRQ_INT1_OVP_EVENT, "muic-ovp-event" },
  219. { SM5504_IRQ_INT1_CONNECT, "muic-connect" },
  220. { SM5504_IRQ_INT1_ADC_CHG, "muic-adc-chg" },
  221. { SM5504_IRQ_INT2_RID_CHG, "muic-rid-chg" },
  222. { SM5504_IRQ_INT2_UVLO, "muic-uvlo" },
  223. { SM5504_IRQ_INT2_POR, "muic-por" },
  224. { SM5504_IRQ_INT2_OVP_FET, "muic-ovp-fet" },
  225. { SM5504_IRQ_INT2_OCP_LATCH, "muic-ocp-latch" },
  226. { SM5504_IRQ_INT2_OCP_EVENT, "muic-ocp-event" },
  227. { SM5504_IRQ_INT2_OVP_OCP_EVENT, "muic-ovp-ocp-event" },
  228. };
  229. /* Define interrupt list of SM5504 to register regmap_irq */
  230. static const struct regmap_irq sm5504_irqs[] = {
  231. /* INT1 interrupts */
  232. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ATTACH_MASK, },
  233. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DETACH_MASK, },
  234. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CHG_DET_MASK, },
  235. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DCD_OUT_MASK, },
  236. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_OVP_MASK, },
  237. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CONNECT_MASK, },
  238. { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ADC_CHG_MASK, },
  239. /* INT2 interrupts */
  240. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_RID_CHG_MASK,},
  241. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_UVLO_MASK, },
  242. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_POR_MASK, },
  243. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_FET_MASK, },
  244. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_LATCH_MASK, },
  245. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_EVENT_MASK, },
  246. { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK, },
  247. };
  248. static const struct regmap_irq_chip sm5504_muic_irq_chip = {
  249. .name = "sm5504",
  250. .status_base = SM5502_REG_INT1,
  251. .mask_base = SM5502_REG_INTMASK1,
  252. .num_regs = 2,
  253. .irqs = sm5504_irqs,
  254. .num_irqs = ARRAY_SIZE(sm5504_irqs),
  255. };
  256. /* Define regmap configuration of SM5502 for I2C communication */
  257. static bool sm5502_muic_volatile_reg(struct device *dev, unsigned int reg)
  258. {
  259. switch (reg) {
  260. case SM5502_REG_INTMASK1:
  261. case SM5502_REG_INTMASK2:
  262. return true;
  263. default:
  264. break;
  265. }
  266. return false;
  267. }
  268. static const struct regmap_config sm5502_muic_regmap_config = {
  269. .reg_bits = 8,
  270. .val_bits = 8,
  271. .volatile_reg = sm5502_muic_volatile_reg,
  272. .max_register = SM5502_REG_END,
  273. };
  274. /* Change DM_CON/DP_CON/VBUSIN switch according to cable type */
  275. static int sm5502_muic_set_path(struct sm5502_muic_info *info,
  276. unsigned int con_sw, unsigned int vbus_sw,
  277. bool attached)
  278. {
  279. int ret;
  280. if (!attached) {
  281. con_sw = DM_DP_SWITCH_OPEN;
  282. vbus_sw = VBUSIN_SWITCH_OPEN;
  283. }
  284. switch (con_sw) {
  285. case DM_DP_SWITCH_OPEN:
  286. case DM_DP_SWITCH_USB:
  287. case DM_DP_SWITCH_AUDIO:
  288. case DM_DP_SWITCH_UART:
  289. ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1,
  290. SM5502_REG_MANUAL_SW1_DP_MASK |
  291. SM5502_REG_MANUAL_SW1_DM_MASK,
  292. con_sw);
  293. if (ret < 0) {
  294. dev_err(info->dev,
  295. "cannot update DM_CON/DP_CON switch\n");
  296. return ret;
  297. }
  298. break;
  299. default:
  300. dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
  301. con_sw);
  302. return -EINVAL;
  303. }
  304. switch (vbus_sw) {
  305. case VBUSIN_SWITCH_OPEN:
  306. case VBUSIN_SWITCH_VBUSOUT:
  307. case VBUSIN_SWITCH_MIC:
  308. case VBUSIN_SWITCH_VBUSOUT_WITH_USB:
  309. ret = regmap_update_bits(info->regmap, SM5502_REG_MANUAL_SW1,
  310. SM5502_REG_MANUAL_SW1_VBUSIN_MASK,
  311. vbus_sw);
  312. if (ret < 0) {
  313. dev_err(info->dev,
  314. "cannot update VBUSIN switch\n");
  315. return ret;
  316. }
  317. break;
  318. default:
  319. dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw);
  320. return -EINVAL;
  321. }
  322. return 0;
  323. }
  324. /* Return cable type of attached or detached accessories */
  325. static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
  326. {
  327. unsigned int cable_type, adc, dev_type1;
  328. int ret;
  329. /* Read ADC value according to external cable or button */
  330. ret = regmap_read(info->regmap, SM5502_REG_ADC, &adc);
  331. if (ret) {
  332. dev_err(info->dev, "failed to read ADC register\n");
  333. return ret;
  334. }
  335. /*
  336. * If ADC is SM5502_MUIC_ADC_GROUND(0x0), external cable hasn't
  337. * connected with to MUIC device.
  338. */
  339. cable_type = adc & SM5502_REG_ADC_MASK;
  340. switch (cable_type) {
  341. case SM5502_MUIC_ADC_GROUND:
  342. ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1,
  343. &dev_type1);
  344. if (ret) {
  345. dev_err(info->dev, "failed to read DEV_TYPE1 reg\n");
  346. return ret;
  347. }
  348. if (dev_type1 == info->type->otg_dev_type1) {
  349. cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG;
  350. } else {
  351. dev_dbg(info->dev,
  352. "cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n",
  353. adc, dev_type1);
  354. return -EINVAL;
  355. }
  356. break;
  357. case SM5502_MUIC_ADC_SEND_END_BUTTON:
  358. case SM5502_MUIC_ADC_REMOTE_S1_BUTTON:
  359. case SM5502_MUIC_ADC_REMOTE_S2_BUTTON:
  360. case SM5502_MUIC_ADC_REMOTE_S3_BUTTON:
  361. case SM5502_MUIC_ADC_REMOTE_S4_BUTTON:
  362. case SM5502_MUIC_ADC_REMOTE_S5_BUTTON:
  363. case SM5502_MUIC_ADC_REMOTE_S6_BUTTON:
  364. case SM5502_MUIC_ADC_REMOTE_S7_BUTTON:
  365. case SM5502_MUIC_ADC_REMOTE_S8_BUTTON:
  366. case SM5502_MUIC_ADC_REMOTE_S9_BUTTON:
  367. case SM5502_MUIC_ADC_REMOTE_S10_BUTTON:
  368. case SM5502_MUIC_ADC_REMOTE_S11_BUTTON:
  369. case SM5502_MUIC_ADC_REMOTE_S12_BUTTON:
  370. case SM5502_MUIC_ADC_RESERVED_ACC_1:
  371. case SM5502_MUIC_ADC_RESERVED_ACC_2:
  372. case SM5502_MUIC_ADC_RESERVED_ACC_3:
  373. case SM5502_MUIC_ADC_RESERVED_ACC_4:
  374. case SM5502_MUIC_ADC_RESERVED_ACC_5:
  375. case SM5502_MUIC_ADC_AUDIO_TYPE2:
  376. case SM5502_MUIC_ADC_PHONE_POWERED_DEV:
  377. case SM5502_MUIC_ADC_TTY_CONVERTER:
  378. case SM5502_MUIC_ADC_UART_CABLE:
  379. case SM5502_MUIC_ADC_TYPE1_CHARGER:
  380. case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB:
  381. case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB:
  382. case SM5502_MUIC_ADC_AUDIO_VIDEO_CABLE:
  383. case SM5502_MUIC_ADC_TYPE2_CHARGER:
  384. case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART:
  385. case SM5502_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART:
  386. break;
  387. case SM5502_MUIC_ADC_AUDIO_TYPE1:
  388. /*
  389. * Check whether cable type is
  390. * SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE
  391. * or SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END
  392. * by using Button event.
  393. */
  394. break;
  395. case SM5502_MUIC_ADC_OPEN:
  396. ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1,
  397. &dev_type1);
  398. if (ret) {
  399. dev_err(info->dev, "failed to read DEV_TYPE1 reg\n");
  400. return ret;
  401. }
  402. if (dev_type1 == info->type->otg_dev_type1) {
  403. cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG;
  404. break;
  405. }
  406. switch (dev_type1) {
  407. case SM5502_REG_DEV_TYPE1_USB_SDP_MASK:
  408. cable_type = SM5502_MUIC_ADC_OPEN_USB;
  409. break;
  410. case SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK:
  411. cable_type = SM5502_MUIC_ADC_OPEN_TA;
  412. break;
  413. default:
  414. dev_dbg(info->dev,
  415. "cannot identify the cable type: adc(0x%x)\n",
  416. adc);
  417. return -EINVAL;
  418. }
  419. break;
  420. default:
  421. dev_err(info->dev,
  422. "failed to identify the cable type: adc(0x%x)\n", adc);
  423. return -EINVAL;
  424. }
  425. return cable_type;
  426. }
  427. static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
  428. bool attached)
  429. {
  430. static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND;
  431. unsigned int cable_type = SM5502_MUIC_ADC_GROUND;
  432. unsigned int con_sw = DM_DP_SWITCH_OPEN;
  433. unsigned int vbus_sw = VBUSIN_SWITCH_OPEN;
  434. unsigned int id;
  435. int ret;
  436. /* Get the type of attached or detached cable */
  437. if (attached)
  438. cable_type = sm5502_muic_get_cable_type(info);
  439. else
  440. cable_type = prev_cable_type;
  441. prev_cable_type = cable_type;
  442. switch (cable_type) {
  443. case SM5502_MUIC_ADC_OPEN_USB:
  444. id = EXTCON_USB;
  445. con_sw = DM_DP_SWITCH_USB;
  446. vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB;
  447. break;
  448. case SM5502_MUIC_ADC_OPEN_TA:
  449. id = EXTCON_CHG_USB_DCP;
  450. con_sw = DM_DP_SWITCH_OPEN;
  451. vbus_sw = VBUSIN_SWITCH_VBUSOUT;
  452. break;
  453. case SM5502_MUIC_ADC_GROUND_USB_OTG:
  454. case SM5502_MUIC_ADC_OPEN_USB_OTG:
  455. id = EXTCON_USB_HOST;
  456. con_sw = DM_DP_SWITCH_USB;
  457. vbus_sw = VBUSIN_SWITCH_OPEN;
  458. break;
  459. default:
  460. dev_dbg(info->dev,
  461. "cannot handle this cable_type (0x%x)\n", cable_type);
  462. return 0;
  463. }
  464. /* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */
  465. ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached);
  466. if (ret < 0)
  467. return ret;
  468. /* Change the state of external accessory */
  469. extcon_set_state_sync(info->edev, id, attached);
  470. if (id == EXTCON_USB)
  471. extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
  472. attached);
  473. return 0;
  474. }
  475. static void sm5502_muic_irq_work(struct work_struct *work)
  476. {
  477. struct sm5502_muic_info *info = container_of(work,
  478. struct sm5502_muic_info, irq_work);
  479. int ret = 0;
  480. if (!info->edev)
  481. return;
  482. mutex_lock(&info->mutex);
  483. /* Detect attached or detached cables */
  484. if (info->irq_attach) {
  485. ret = sm5502_muic_cable_handler(info, true);
  486. info->irq_attach = false;
  487. }
  488. if (info->irq_detach) {
  489. ret = sm5502_muic_cable_handler(info, false);
  490. info->irq_detach = false;
  491. }
  492. if (ret < 0)
  493. dev_err(info->dev, "failed to handle MUIC interrupt\n");
  494. mutex_unlock(&info->mutex);
  495. }
  496. /*
  497. * Sets irq_attach or irq_detach in sm5502_muic_info and returns 0.
  498. * Returns -ESRCH if irq_type does not match registered IRQ for this dev type.
  499. */
  500. static int sm5502_parse_irq(struct sm5502_muic_info *info, int irq_type)
  501. {
  502. switch (irq_type) {
  503. case SM5502_IRQ_INT1_ATTACH:
  504. info->irq_attach = true;
  505. break;
  506. case SM5502_IRQ_INT1_DETACH:
  507. info->irq_detach = true;
  508. break;
  509. case SM5502_IRQ_INT1_KP:
  510. case SM5502_IRQ_INT1_LKP:
  511. case SM5502_IRQ_INT1_LKR:
  512. case SM5502_IRQ_INT1_OVP_EVENT:
  513. case SM5502_IRQ_INT1_OCP_EVENT:
  514. case SM5502_IRQ_INT1_OVP_OCP_DIS:
  515. case SM5502_IRQ_INT2_VBUS_DET:
  516. case SM5502_IRQ_INT2_REV_ACCE:
  517. case SM5502_IRQ_INT2_ADC_CHG:
  518. case SM5502_IRQ_INT2_STUCK_KEY:
  519. case SM5502_IRQ_INT2_STUCK_KEY_RCV:
  520. case SM5502_IRQ_INT2_MHL:
  521. default:
  522. break;
  523. }
  524. return 0;
  525. }
  526. static int sm5504_parse_irq(struct sm5502_muic_info *info, int irq_type)
  527. {
  528. switch (irq_type) {
  529. case SM5504_IRQ_INT1_ATTACH:
  530. info->irq_attach = true;
  531. break;
  532. case SM5504_IRQ_INT1_DETACH:
  533. info->irq_detach = true;
  534. break;
  535. case SM5504_IRQ_INT1_CHG_DET:
  536. case SM5504_IRQ_INT1_DCD_OUT:
  537. case SM5504_IRQ_INT1_OVP_EVENT:
  538. case SM5504_IRQ_INT1_CONNECT:
  539. case SM5504_IRQ_INT1_ADC_CHG:
  540. case SM5504_IRQ_INT2_RID_CHG:
  541. case SM5504_IRQ_INT2_UVLO:
  542. case SM5504_IRQ_INT2_POR:
  543. case SM5504_IRQ_INT2_OVP_FET:
  544. case SM5504_IRQ_INT2_OCP_LATCH:
  545. case SM5504_IRQ_INT2_OCP_EVENT:
  546. case SM5504_IRQ_INT2_OVP_OCP_EVENT:
  547. default:
  548. break;
  549. }
  550. return 0;
  551. }
  552. static irqreturn_t sm5502_muic_irq_handler(int irq, void *data)
  553. {
  554. struct sm5502_muic_info *info = data;
  555. int i, irq_type = -1, ret;
  556. for (i = 0; i < info->type->num_muic_irqs; i++)
  557. if (irq == info->type->muic_irqs[i].virq)
  558. irq_type = info->type->muic_irqs[i].irq;
  559. ret = info->type->parse_irq(info, irq_type);
  560. if (ret < 0) {
  561. dev_warn(info->dev, "cannot handle is interrupt:%d\n",
  562. irq_type);
  563. return IRQ_HANDLED;
  564. }
  565. schedule_work(&info->irq_work);
  566. return IRQ_HANDLED;
  567. }
  568. static void sm5502_muic_detect_cable_wq(struct work_struct *work)
  569. {
  570. struct sm5502_muic_info *info = container_of(to_delayed_work(work),
  571. struct sm5502_muic_info, wq_detcable);
  572. int ret;
  573. /* Notify the state of connector cable or not */
  574. ret = sm5502_muic_cable_handler(info, true);
  575. if (ret < 0)
  576. dev_warn(info->dev, "failed to detect cable state\n");
  577. }
  578. static void sm5502_init_dev_type(struct sm5502_muic_info *info)
  579. {
  580. unsigned int reg_data, vendor_id, version_id;
  581. int i, ret;
  582. /* To test I2C, Print version_id and vendor_id of SM5502 */
  583. ret = regmap_read(info->regmap, SM5502_REG_DEVICE_ID, &reg_data);
  584. if (ret) {
  585. dev_err(info->dev,
  586. "failed to read DEVICE_ID register: %d\n", ret);
  587. return;
  588. }
  589. vendor_id = ((reg_data & SM5502_REG_DEVICE_ID_VENDOR_MASK) >>
  590. SM5502_REG_DEVICE_ID_VENDOR_SHIFT);
  591. version_id = ((reg_data & SM5502_REG_DEVICE_ID_VERSION_MASK) >>
  592. SM5502_REG_DEVICE_ID_VERSION_SHIFT);
  593. dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n",
  594. version_id, vendor_id);
  595. /* Initiazle the register of SM5502 device to bring-up */
  596. for (i = 0; i < info->type->num_reg_data; i++) {
  597. unsigned int val = 0;
  598. if (!info->type->reg_data[i].invert)
  599. val |= ~info->type->reg_data[i].val;
  600. else
  601. val = info->type->reg_data[i].val;
  602. regmap_write(info->regmap, info->type->reg_data[i].reg, val);
  603. }
  604. }
  605. static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
  606. {
  607. struct device_node *np = i2c->dev.of_node;
  608. struct sm5502_muic_info *info;
  609. int i, ret, irq_flags;
  610. if (!np)
  611. return -EINVAL;
  612. info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
  613. if (!info)
  614. return -ENOMEM;
  615. i2c_set_clientdata(i2c, info);
  616. info->dev = &i2c->dev;
  617. info->i2c = i2c;
  618. info->irq = i2c->irq;
  619. info->type = device_get_match_data(info->dev);
  620. if (!info->type)
  621. return -EINVAL;
  622. if (!info->type->parse_irq) {
  623. dev_err(info->dev, "parse_irq missing in struct sm5502_type\n");
  624. return -EINVAL;
  625. }
  626. mutex_init(&info->mutex);
  627. INIT_WORK(&info->irq_work, sm5502_muic_irq_work);
  628. info->regmap = devm_regmap_init_i2c(i2c, &sm5502_muic_regmap_config);
  629. if (IS_ERR(info->regmap)) {
  630. ret = PTR_ERR(info->regmap);
  631. dev_err(info->dev, "failed to allocate register map: %d\n",
  632. ret);
  633. return ret;
  634. }
  635. /* Support irq domain for SM5502 MUIC device */
  636. irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
  637. ret = devm_regmap_add_irq_chip(info->dev, info->regmap, info->irq,
  638. irq_flags, 0, info->type->irq_chip,
  639. &info->irq_data);
  640. if (ret != 0) {
  641. dev_err(info->dev, "failed to request IRQ %d: %d\n",
  642. info->irq, ret);
  643. return ret;
  644. }
  645. for (i = 0; i < info->type->num_muic_irqs; i++) {
  646. struct muic_irq *muic_irq = &info->type->muic_irqs[i];
  647. int virq = 0;
  648. virq = regmap_irq_get_virq(info->irq_data, muic_irq->irq);
  649. if (virq <= 0)
  650. return -EINVAL;
  651. muic_irq->virq = virq;
  652. ret = devm_request_threaded_irq(info->dev, virq, NULL,
  653. sm5502_muic_irq_handler,
  654. IRQF_NO_SUSPEND | IRQF_ONESHOT,
  655. muic_irq->name, info);
  656. if (ret) {
  657. dev_err(info->dev,
  658. "failed: irq request (IRQ: %d, error :%d)\n",
  659. muic_irq->irq, ret);
  660. return ret;
  661. }
  662. }
  663. /* Allocate extcon device */
  664. info->edev = devm_extcon_dev_allocate(info->dev, sm5502_extcon_cable);
  665. if (IS_ERR(info->edev)) {
  666. dev_err(info->dev, "failed to allocate memory for extcon\n");
  667. return -ENOMEM;
  668. }
  669. /* Register extcon device */
  670. ret = devm_extcon_dev_register(info->dev, info->edev);
  671. if (ret) {
  672. dev_err(info->dev, "failed to register extcon device\n");
  673. return ret;
  674. }
  675. /*
  676. * Detect accessory after completing the initialization of platform
  677. *
  678. * - Use delayed workqueue to detect cable state and then
  679. * notify cable state to notifiee/platform through uevent.
  680. * After completing the booting of platform, the extcon provider
  681. * driver should notify cable state to upper layer.
  682. */
  683. INIT_DELAYED_WORK(&info->wq_detcable, sm5502_muic_detect_cable_wq);
  684. queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
  685. msecs_to_jiffies(DELAY_MS_DEFAULT));
  686. /* Initialize SM5502 device and print vendor id and version id */
  687. sm5502_init_dev_type(info);
  688. return 0;
  689. }
  690. static const struct sm5502_type sm5502_data = {
  691. .muic_irqs = sm5502_muic_irqs,
  692. .num_muic_irqs = ARRAY_SIZE(sm5502_muic_irqs),
  693. .irq_chip = &sm5502_muic_irq_chip,
  694. .reg_data = sm5502_reg_data,
  695. .num_reg_data = ARRAY_SIZE(sm5502_reg_data),
  696. .otg_dev_type1 = SM5502_REG_DEV_TYPE1_USB_OTG_MASK,
  697. .parse_irq = sm5502_parse_irq,
  698. };
  699. static const struct sm5502_type sm5504_data = {
  700. .muic_irqs = sm5504_muic_irqs,
  701. .num_muic_irqs = ARRAY_SIZE(sm5504_muic_irqs),
  702. .irq_chip = &sm5504_muic_irq_chip,
  703. .reg_data = sm5504_reg_data,
  704. .num_reg_data = ARRAY_SIZE(sm5504_reg_data),
  705. .otg_dev_type1 = SM5504_REG_DEV_TYPE1_USB_OTG_MASK,
  706. .parse_irq = sm5504_parse_irq,
  707. };
  708. static const struct of_device_id sm5502_dt_match[] = {
  709. { .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data },
  710. { .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data },
  711. { .compatible = "siliconmitus,sm5703-muic", .data = &sm5502_data },
  712. { },
  713. };
  714. MODULE_DEVICE_TABLE(of, sm5502_dt_match);
  715. #ifdef CONFIG_PM_SLEEP
  716. static int sm5502_muic_suspend(struct device *dev)
  717. {
  718. struct i2c_client *i2c = to_i2c_client(dev);
  719. struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
  720. enable_irq_wake(info->irq);
  721. return 0;
  722. }
  723. static int sm5502_muic_resume(struct device *dev)
  724. {
  725. struct i2c_client *i2c = to_i2c_client(dev);
  726. struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
  727. disable_irq_wake(info->irq);
  728. return 0;
  729. }
  730. #endif
  731. static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops,
  732. sm5502_muic_suspend, sm5502_muic_resume);
  733. static const struct i2c_device_id sm5502_i2c_id[] = {
  734. { "sm5502", (kernel_ulong_t)&sm5502_data },
  735. { "sm5504", (kernel_ulong_t)&sm5504_data },
  736. { "sm5703-muic", (kernel_ulong_t)&sm5502_data },
  737. { }
  738. };
  739. MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id);
  740. static struct i2c_driver sm5502_muic_i2c_driver = {
  741. .driver = {
  742. .name = "sm5502",
  743. .pm = &sm5502_muic_pm_ops,
  744. .of_match_table = sm5502_dt_match,
  745. },
  746. .probe_new = sm5022_muic_i2c_probe,
  747. .id_table = sm5502_i2c_id,
  748. };
  749. static int __init sm5502_muic_i2c_init(void)
  750. {
  751. return i2c_add_driver(&sm5502_muic_i2c_driver);
  752. }
  753. subsys_initcall(sm5502_muic_i2c_init);
  754. MODULE_DESCRIPTION("Silicon Mitus SM5502 Extcon driver");
  755. MODULE_AUTHOR("Chanwoo Choi <[email protected]>");
  756. MODULE_LICENSE("GPL");