extcon.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417
  1. /*
  2. * drivers/extcon/extcon.c - External Connector (extcon) framework.
  3. *
  4. * External connector (extcon) class driver
  5. *
  6. * Copyright (C) 2015 Samsung Electronics
  7. * Author: Chanwoo Choi <cw00.choi@samsung.com>
  8. *
  9. * Copyright (C) 2012 Samsung Electronics
  10. * Author: Donggeun Kim <dg77.kim@samsung.com>
  11. * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
  12. *
  13. * based on android/drivers/switch/switch_class.c
  14. * Copyright (C) 2008 Google, Inc.
  15. * Author: Mike Lockwood <lockwood@android.com>
  16. *
  17. * This software is licensed under the terms of the GNU General Public
  18. * License version 2, as published by the Free Software Foundation, and
  19. * may be copied, distributed, and modified under those terms.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. */
  26. #include <linux/module.h>
  27. #include <linux/types.h>
  28. #include <linux/init.h>
  29. #include <linux/device.h>
  30. #include <linux/fs.h>
  31. #include <linux/err.h>
  32. #include <linux/of.h>
  33. #include <linux/slab.h>
  34. #include <linux/sysfs.h>
  35. #include "extcon.h"
  36. #define SUPPORTED_CABLE_MAX 32
  37. struct __extcon_info {
  38. unsigned int type;
  39. unsigned int id;
  40. const char *name;
  41. } extcon_info[] = {
  42. [EXTCON_NONE] = {
  43. .type = EXTCON_TYPE_MISC,
  44. .id = EXTCON_NONE,
  45. .name = "NONE",
  46. },
  47. /* USB external connector */
  48. [EXTCON_USB] = {
  49. .type = EXTCON_TYPE_USB,
  50. .id = EXTCON_USB,
  51. .name = "USB",
  52. },
  53. [EXTCON_USB_HOST] = {
  54. .type = EXTCON_TYPE_USB,
  55. .id = EXTCON_USB_HOST,
  56. .name = "USB-HOST",
  57. },
  58. /* Charging external connector */
  59. [EXTCON_CHG_USB_SDP] = {
  60. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  61. .id = EXTCON_CHG_USB_SDP,
  62. .name = "SDP",
  63. },
  64. [EXTCON_CHG_USB_DCP] = {
  65. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  66. .id = EXTCON_CHG_USB_DCP,
  67. .name = "DCP",
  68. },
  69. [EXTCON_CHG_USB_CDP] = {
  70. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  71. .id = EXTCON_CHG_USB_CDP,
  72. .name = "CDP",
  73. },
  74. [EXTCON_CHG_USB_ACA] = {
  75. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  76. .id = EXTCON_CHG_USB_ACA,
  77. .name = "ACA",
  78. },
  79. [EXTCON_CHG_USB_FAST] = {
  80. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  81. .id = EXTCON_CHG_USB_FAST,
  82. .name = "FAST-CHARGER",
  83. },
  84. [EXTCON_CHG_USB_SLOW] = {
  85. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  86. .id = EXTCON_CHG_USB_SLOW,
  87. .name = "SLOW-CHARGER",
  88. },
  89. [EXTCON_CHG_WPT] = {
  90. .type = EXTCON_TYPE_CHG,
  91. .id = EXTCON_CHG_WPT,
  92. .name = "WPT",
  93. },
  94. [EXTCON_CHG_USB_PD] = {
  95. .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
  96. .id = EXTCON_CHG_USB_PD,
  97. .name = "PD",
  98. },
  99. /* Jack external connector */
  100. [EXTCON_JACK_MICROPHONE] = {
  101. .type = EXTCON_TYPE_JACK,
  102. .id = EXTCON_JACK_MICROPHONE,
  103. .name = "MICROPHONE",
  104. },
  105. [EXTCON_JACK_HEADPHONE] = {
  106. .type = EXTCON_TYPE_JACK,
  107. .id = EXTCON_JACK_HEADPHONE,
  108. .name = "HEADPHONE",
  109. },
  110. [EXTCON_JACK_LINE_IN] = {
  111. .type = EXTCON_TYPE_JACK,
  112. .id = EXTCON_JACK_LINE_IN,
  113. .name = "LINE-IN",
  114. },
  115. [EXTCON_JACK_LINE_OUT] = {
  116. .type = EXTCON_TYPE_JACK,
  117. .id = EXTCON_JACK_LINE_OUT,
  118. .name = "LINE-OUT",
  119. },
  120. [EXTCON_JACK_VIDEO_IN] = {
  121. .type = EXTCON_TYPE_JACK,
  122. .id = EXTCON_JACK_VIDEO_IN,
  123. .name = "VIDEO-IN",
  124. },
  125. [EXTCON_JACK_VIDEO_OUT] = {
  126. .type = EXTCON_TYPE_JACK,
  127. .id = EXTCON_JACK_VIDEO_OUT,
  128. .name = "VIDEO-OUT",
  129. },
  130. [EXTCON_JACK_SPDIF_IN] = {
  131. .type = EXTCON_TYPE_JACK,
  132. .id = EXTCON_JACK_SPDIF_IN,
  133. .name = "SPDIF-IN",
  134. },
  135. [EXTCON_JACK_SPDIF_OUT] = {
  136. .type = EXTCON_TYPE_JACK,
  137. .id = EXTCON_JACK_SPDIF_OUT,
  138. .name = "SPDIF-OUT",
  139. },
  140. /* Display external connector */
  141. [EXTCON_DISP_HDMI] = {
  142. .type = EXTCON_TYPE_DISP,
  143. .id = EXTCON_DISP_HDMI,
  144. .name = "HDMI",
  145. },
  146. [EXTCON_DISP_MHL] = {
  147. .type = EXTCON_TYPE_DISP,
  148. .id = EXTCON_DISP_MHL,
  149. .name = "MHL",
  150. },
  151. [EXTCON_DISP_DVI] = {
  152. .type = EXTCON_TYPE_DISP,
  153. .id = EXTCON_DISP_DVI,
  154. .name = "DVI",
  155. },
  156. [EXTCON_DISP_VGA] = {
  157. .type = EXTCON_TYPE_DISP,
  158. .id = EXTCON_DISP_VGA,
  159. .name = "VGA",
  160. },
  161. [EXTCON_DISP_DP] = {
  162. .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB,
  163. .id = EXTCON_DISP_DP,
  164. .name = "DP",
  165. },
  166. [EXTCON_DISP_HMD] = {
  167. .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB,
  168. .id = EXTCON_DISP_HMD,
  169. .name = "HMD",
  170. },
  171. /* Miscellaneous external connector */
  172. [EXTCON_DOCK] = {
  173. .type = EXTCON_TYPE_MISC,
  174. .id = EXTCON_DOCK,
  175. .name = "DOCK",
  176. },
  177. [EXTCON_JIG] = {
  178. .type = EXTCON_TYPE_MISC,
  179. .id = EXTCON_JIG,
  180. .name = "JIG",
  181. },
  182. [EXTCON_MECHANICAL] = {
  183. .type = EXTCON_TYPE_MISC,
  184. .id = EXTCON_MECHANICAL,
  185. .name = "MECHANICAL",
  186. },
  187. { /* sentinel */ }
  188. };
  189. /**
  190. * struct extcon_cable - An internal data for each cable of extcon device.
  191. * @edev: The extcon device
  192. * @cable_index: Index of this cable in the edev
  193. * @attr_g: Attribute group for the cable
  194. * @attr_name: "name" sysfs entry
  195. * @attr_state: "state" sysfs entry
  196. * @attrs: Array pointing to attr_name and attr_state for attr_g
  197. */
  198. struct extcon_cable {
  199. struct extcon_dev *edev;
  200. int cable_index;
  201. struct attribute_group attr_g;
  202. struct device_attribute attr_name;
  203. struct device_attribute attr_state;
  204. struct attribute *attrs[3]; /* to be fed to attr_g.attrs */
  205. union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT];
  206. union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT];
  207. union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT];
  208. union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT];
  209. unsigned long usb_bits[BITS_TO_LONGS(EXTCON_PROP_USB_CNT)];
  210. unsigned long chg_bits[BITS_TO_LONGS(EXTCON_PROP_CHG_CNT)];
  211. unsigned long jack_bits[BITS_TO_LONGS(EXTCON_PROP_JACK_CNT)];
  212. unsigned long disp_bits[BITS_TO_LONGS(EXTCON_PROP_DISP_CNT)];
  213. };
  214. static struct class *extcon_class;
  215. static LIST_HEAD(extcon_dev_list);
  216. static DEFINE_MUTEX(extcon_dev_list_lock);
  217. /**
  218. * check_mutually_exclusive - Check if new_state violates mutually_exclusive
  219. * condition.
  220. * @edev: the extcon device
  221. * @new_state: new cable attach status for @edev
  222. *
  223. * Returns 0 if nothing violates. Returns the index + 1 for the first
  224. * violated condition.
  225. */
  226. static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
  227. {
  228. int i = 0;
  229. if (!edev->mutually_exclusive)
  230. return 0;
  231. for (i = 0; edev->mutually_exclusive[i]; i++) {
  232. int weight;
  233. u32 correspondants = new_state & edev->mutually_exclusive[i];
  234. /* calculate the total number of bits set */
  235. weight = hweight32(correspondants);
  236. if (weight > 1)
  237. return i + 1;
  238. }
  239. return 0;
  240. }
  241. static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id)
  242. {
  243. int i;
  244. /* Find the the index of extcon cable in edev->supported_cable */
  245. for (i = 0; i < edev->max_supported; i++) {
  246. if (edev->supported_cable[i] == id)
  247. return i;
  248. }
  249. return -EINVAL;
  250. }
  251. static int get_extcon_type(unsigned int prop)
  252. {
  253. switch (prop) {
  254. case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX:
  255. return EXTCON_TYPE_USB;
  256. case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX:
  257. return EXTCON_TYPE_CHG;
  258. case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX:
  259. return EXTCON_TYPE_JACK;
  260. case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX:
  261. return EXTCON_TYPE_DISP;
  262. default:
  263. return -EINVAL;
  264. }
  265. }
  266. static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index)
  267. {
  268. return !!(edev->state & BIT(index));
  269. }
  270. static bool is_extcon_changed(struct extcon_dev *edev, int index,
  271. bool new_state)
  272. {
  273. int state = !!(edev->state & BIT(index));
  274. return (state != new_state);
  275. }
  276. static bool is_extcon_property_supported(unsigned int id, unsigned int prop)
  277. {
  278. int type;
  279. /* Check whether the property is supported or not. */
  280. type = get_extcon_type(prop);
  281. if (type < 0)
  282. return false;
  283. /* Check whether a specific extcon id supports the property or not. */
  284. return !!(extcon_info[id].type & type);
  285. }
  286. static int is_extcon_property_capability(struct extcon_dev *edev,
  287. unsigned int id, int index,unsigned int prop)
  288. {
  289. struct extcon_cable *cable;
  290. int type, ret;
  291. /* Check whether the property is supported or not. */
  292. type = get_extcon_type(prop);
  293. if (type < 0)
  294. return type;
  295. cable = &edev->cables[index];
  296. switch (type) {
  297. case EXTCON_TYPE_USB:
  298. ret = test_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits);
  299. break;
  300. case EXTCON_TYPE_CHG:
  301. ret = test_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits);
  302. break;
  303. case EXTCON_TYPE_JACK:
  304. ret = test_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits);
  305. break;
  306. case EXTCON_TYPE_DISP:
  307. ret = test_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits);
  308. break;
  309. default:
  310. ret = -EINVAL;
  311. }
  312. return ret;
  313. }
  314. static void init_property(struct extcon_dev *edev, unsigned int id, int index)
  315. {
  316. unsigned int type = extcon_info[id].type;
  317. struct extcon_cable *cable = &edev->cables[index];
  318. if (EXTCON_TYPE_USB & type)
  319. memset(cable->usb_propval, 0, sizeof(cable->usb_propval));
  320. if (EXTCON_TYPE_CHG & type)
  321. memset(cable->chg_propval, 0, sizeof(cable->chg_propval));
  322. if (EXTCON_TYPE_JACK & type)
  323. memset(cable->jack_propval, 0, sizeof(cable->jack_propval));
  324. if (EXTCON_TYPE_DISP & type)
  325. memset(cable->disp_propval, 0, sizeof(cable->disp_propval));
  326. }
  327. static ssize_t state_show(struct device *dev, struct device_attribute *attr,
  328. char *buf)
  329. {
  330. int i, count = 0;
  331. struct extcon_dev *edev = dev_get_drvdata(dev);
  332. if (edev->max_supported == 0)
  333. return sprintf(buf, "%u\n", edev->state);
  334. for (i = 0; i < edev->max_supported; i++) {
  335. count += sprintf(buf + count, "%s=%d\n",
  336. extcon_info[edev->supported_cable[i]].name,
  337. !!(edev->state & BIT(i)));
  338. }
  339. return count;
  340. }
  341. static DEVICE_ATTR_RO(state);
  342. static ssize_t name_show(struct device *dev, struct device_attribute *attr,
  343. char *buf)
  344. {
  345. struct extcon_dev *edev = dev_get_drvdata(dev);
  346. return sprintf(buf, "%s\n", edev->name);
  347. }
  348. static DEVICE_ATTR_RO(name);
  349. static ssize_t cable_name_show(struct device *dev,
  350. struct device_attribute *attr, char *buf)
  351. {
  352. struct extcon_cable *cable = container_of(attr, struct extcon_cable,
  353. attr_name);
  354. int i = cable->cable_index;
  355. return sprintf(buf, "%s\n",
  356. extcon_info[cable->edev->supported_cable[i]].name);
  357. }
  358. static ssize_t cable_state_show(struct device *dev,
  359. struct device_attribute *attr, char *buf)
  360. {
  361. struct extcon_cable *cable = container_of(attr, struct extcon_cable,
  362. attr_state);
  363. int i = cable->cable_index;
  364. return sprintf(buf, "%d\n",
  365. extcon_get_state(cable->edev, cable->edev->supported_cable[i]));
  366. }
  367. /**
  368. * extcon_sync() - Synchronize the states for both the attached/detached
  369. * @edev: the extcon device that has the cable.
  370. *
  371. * This function send a notification to synchronize the all states of a
  372. * specific external connector
  373. */
  374. int extcon_sync(struct extcon_dev *edev, unsigned int id)
  375. {
  376. char name_buf[120];
  377. char state_buf[120];
  378. char *prop_buf;
  379. char *envp[3];
  380. int env_offset = 0;
  381. int length;
  382. int index;
  383. int state;
  384. unsigned long flags;
  385. if (!edev)
  386. return -EINVAL;
  387. index = find_cable_index_by_id(edev, id);
  388. if (index < 0)
  389. return index;
  390. spin_lock_irqsave(&edev->lock, flags);
  391. state = !!(edev->state & BIT(index));
  392. /*
  393. * Call functions in a raw notifier chain for the specific one
  394. * external connector.
  395. */
  396. raw_notifier_call_chain(&edev->nh[index], state, edev);
  397. /*
  398. * Call functions in a raw notifier chain for the all supported
  399. * external connectors.
  400. */
  401. raw_notifier_call_chain(&edev->nh_all, state, edev);
  402. /* This could be in interrupt handler */
  403. prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
  404. if (!prop_buf) {
  405. /* Unlock early before uevent */
  406. spin_unlock_irqrestore(&edev->lock, flags);
  407. dev_err(&edev->dev, "out of memory in extcon_set_state\n");
  408. kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
  409. return -ENOMEM;
  410. }
  411. length = name_show(&edev->dev, NULL, prop_buf);
  412. if (length > 0) {
  413. if (prop_buf[length - 1] == '\n')
  414. prop_buf[length - 1] = 0;
  415. snprintf(name_buf, sizeof(name_buf), "NAME=%s", prop_buf);
  416. envp[env_offset++] = name_buf;
  417. }
  418. length = state_show(&edev->dev, NULL, prop_buf);
  419. if (length > 0) {
  420. if (prop_buf[length - 1] == '\n')
  421. prop_buf[length - 1] = 0;
  422. snprintf(state_buf, sizeof(state_buf), "STATE=%s", prop_buf);
  423. envp[env_offset++] = state_buf;
  424. }
  425. envp[env_offset] = NULL;
  426. /* Unlock early before uevent */
  427. spin_unlock_irqrestore(&edev->lock, flags);
  428. kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp);
  429. free_page((unsigned long)prop_buf);
  430. return 0;
  431. }
  432. EXPORT_SYMBOL_GPL(extcon_sync);
  433. /**
  434. * extcon_get_state() - Get the state of a external connector.
  435. * @edev: the extcon device that has the cable.
  436. * @id: the unique id of each external connector in extcon enumeration.
  437. */
  438. int extcon_get_state(struct extcon_dev *edev, const unsigned int id)
  439. {
  440. int index, state;
  441. unsigned long flags;
  442. if (!edev)
  443. return -EINVAL;
  444. index = find_cable_index_by_id(edev, id);
  445. if (index < 0)
  446. return index;
  447. spin_lock_irqsave(&edev->lock, flags);
  448. state = is_extcon_attached(edev, index);
  449. spin_unlock_irqrestore(&edev->lock, flags);
  450. return state;
  451. }
  452. EXPORT_SYMBOL_GPL(extcon_get_state);
  453. /**
  454. * extcon_set_state() - Set the state of a external connector.
  455. * without a notification.
  456. * @edev: the extcon device that has the cable.
  457. * @id: the unique id of each external connector
  458. * in extcon enumeration.
  459. * @state: the new cable status. The default semantics is
  460. * true: attached / false: detached.
  461. *
  462. * This function only set the state of a external connector without
  463. * a notification. To synchronize the data of a external connector,
  464. * use extcon_set_state_sync() and extcon_sync().
  465. */
  466. int extcon_set_state(struct extcon_dev *edev, unsigned int id,
  467. bool cable_state)
  468. {
  469. unsigned long flags;
  470. int index, ret = 0;
  471. if (!edev)
  472. return -EINVAL;
  473. index = find_cable_index_by_id(edev, id);
  474. if (index < 0)
  475. return index;
  476. spin_lock_irqsave(&edev->lock, flags);
  477. /* Check whether the external connector's state is changed. */
  478. if (!is_extcon_changed(edev, index, cable_state))
  479. goto out;
  480. if (check_mutually_exclusive(edev,
  481. (edev->state & ~BIT(index)) | (cable_state & BIT(index)))) {
  482. ret = -EPERM;
  483. goto out;
  484. }
  485. /*
  486. * Initialize the value of extcon property before setting
  487. * the detached state for an external connector.
  488. */
  489. if (!cable_state)
  490. init_property(edev, id, index);
  491. /* Update the state for a external connector. */
  492. if (cable_state)
  493. edev->state |= BIT(index);
  494. else
  495. edev->state &= ~(BIT(index));
  496. out:
  497. spin_unlock_irqrestore(&edev->lock, flags);
  498. return ret;
  499. }
  500. EXPORT_SYMBOL_GPL(extcon_set_state);
  501. /**
  502. * extcon_set_state_sync() - Set the state of a external connector
  503. * with a notification.
  504. * @edev: the extcon device that has the cable.
  505. * @id: the unique id of each external connector
  506. * in extcon enumeration.
  507. * @state: the new cable status. The default semantics is
  508. * true: attached / false: detached.
  509. *
  510. * This function set the state of external connector and synchronize the data
  511. * by usning a notification.
  512. */
  513. int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
  514. bool cable_state)
  515. {
  516. int ret, index;
  517. unsigned long flags;
  518. index = find_cable_index_by_id(edev, id);
  519. if (index < 0)
  520. return index;
  521. /* Check whether the external connector's state is changed. */
  522. spin_lock_irqsave(&edev->lock, flags);
  523. ret = is_extcon_changed(edev, index, cable_state);
  524. spin_unlock_irqrestore(&edev->lock, flags);
  525. if (!ret)
  526. return 0;
  527. ret = extcon_set_state(edev, id, cable_state);
  528. if (ret < 0)
  529. return ret;
  530. return extcon_sync(edev, id);
  531. }
  532. EXPORT_SYMBOL_GPL(extcon_set_state_sync);
  533. /**
  534. * extcon_get_property() - Get the property value of a specific cable.
  535. * @edev: the extcon device that has the cable.
  536. * @id: the unique id of each external connector
  537. * in extcon enumeration.
  538. * @prop: the property id among enum extcon_property.
  539. * @prop_val: the pointer which store the value of property.
  540. *
  541. * When getting the property value of external connector, the external connector
  542. * should be attached. If detached state, function just return 0 without
  543. * property value. Also, the each property should be included in the list of
  544. * supported properties according to the type of external connectors.
  545. *
  546. * Returns 0 if success or error number if fail
  547. */
  548. int extcon_get_property(struct extcon_dev *edev, unsigned int id,
  549. unsigned int prop,
  550. union extcon_property_value *prop_val)
  551. {
  552. struct extcon_cable *cable;
  553. unsigned long flags;
  554. int index, ret = 0;
  555. *prop_val = (union extcon_property_value)(0);
  556. if (!edev)
  557. return -EINVAL;
  558. /* Check whether the property is supported or not */
  559. if (!is_extcon_property_supported(id, prop))
  560. return -EINVAL;
  561. /* Find the cable index of external connector by using id */
  562. index = find_cable_index_by_id(edev, id);
  563. if (index < 0)
  564. return index;
  565. spin_lock_irqsave(&edev->lock, flags);
  566. /* Check whether the property is available or not. */
  567. if (!is_extcon_property_capability(edev, id, index, prop)) {
  568. spin_unlock_irqrestore(&edev->lock, flags);
  569. return -EPERM;
  570. }
  571. /*
  572. * Check whether the external connector is attached.
  573. * If external connector is detached, the user can not
  574. * get the property value.
  575. */
  576. if (!is_extcon_attached(edev, index)) {
  577. spin_unlock_irqrestore(&edev->lock, flags);
  578. return 0;
  579. }
  580. cable = &edev->cables[index];
  581. /* Get the property value according to extcon type */
  582. switch (prop) {
  583. case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX:
  584. *prop_val = cable->usb_propval[prop - EXTCON_PROP_USB_MIN];
  585. break;
  586. case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX:
  587. *prop_val = cable->chg_propval[prop - EXTCON_PROP_CHG_MIN];
  588. break;
  589. case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX:
  590. *prop_val = cable->jack_propval[prop - EXTCON_PROP_JACK_MIN];
  591. break;
  592. case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX:
  593. *prop_val = cable->disp_propval[prop - EXTCON_PROP_DISP_MIN];
  594. break;
  595. default:
  596. ret = -EINVAL;
  597. break;
  598. }
  599. spin_unlock_irqrestore(&edev->lock, flags);
  600. return ret;
  601. }
  602. EXPORT_SYMBOL_GPL(extcon_get_property);
  603. /**
  604. * extcon_set_property() - Set the property value of a specific cable.
  605. * @edev: the extcon device that has the cable.
  606. * @id: the unique id of each external connector
  607. * in extcon enumeration.
  608. * @prop: the property id among enum extcon_property.
  609. * @prop_val: the pointer including the new value of property.
  610. *
  611. * The each property should be included in the list of supported properties
  612. * according to the type of external connectors.
  613. *
  614. * Returns 0 if success or error number if fail
  615. */
  616. int extcon_set_property(struct extcon_dev *edev, unsigned int id,
  617. unsigned int prop,
  618. union extcon_property_value prop_val)
  619. {
  620. struct extcon_cable *cable;
  621. unsigned long flags;
  622. int index, ret = 0;
  623. if (!edev)
  624. return -EINVAL;
  625. /* Check whether the property is supported or not */
  626. if (!is_extcon_property_supported(id, prop))
  627. return -EINVAL;
  628. /* Find the cable index of external connector by using id */
  629. index = find_cable_index_by_id(edev, id);
  630. if (index < 0)
  631. return index;
  632. spin_lock_irqsave(&edev->lock, flags);
  633. /* Check whether the property is available or not. */
  634. if (!is_extcon_property_capability(edev, id, index, prop)) {
  635. spin_unlock_irqrestore(&edev->lock, flags);
  636. return -EPERM;
  637. }
  638. cable = &edev->cables[index];
  639. /* Set the property value according to extcon type */
  640. switch (prop) {
  641. case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX:
  642. cable->usb_propval[prop - EXTCON_PROP_USB_MIN] = prop_val;
  643. break;
  644. case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX:
  645. cable->chg_propval[prop - EXTCON_PROP_CHG_MIN] = prop_val;
  646. break;
  647. case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX:
  648. cable->jack_propval[prop - EXTCON_PROP_JACK_MIN] = prop_val;
  649. break;
  650. case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX:
  651. cable->disp_propval[prop - EXTCON_PROP_DISP_MIN] = prop_val;
  652. break;
  653. default:
  654. ret = -EINVAL;
  655. break;
  656. }
  657. spin_unlock_irqrestore(&edev->lock, flags);
  658. return ret;
  659. }
  660. EXPORT_SYMBOL_GPL(extcon_set_property);
  661. /**
  662. * extcon_set_property_sync() - Set the property value of a specific cable
  663. with a notification.
  664. * @prop_val: the pointer including the new value of property.
  665. *
  666. * When setting the property value of external connector, the external connector
  667. * should be attached. The each property should be included in the list of
  668. * supported properties according to the type of external connectors.
  669. *
  670. * Returns 0 if success or error number if fail
  671. */
  672. int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
  673. unsigned int prop,
  674. union extcon_property_value prop_val)
  675. {
  676. int ret;
  677. ret = extcon_set_property(edev, id, prop, prop_val);
  678. if (ret < 0)
  679. return ret;
  680. return extcon_sync(edev, id);
  681. }
  682. EXPORT_SYMBOL_GPL(extcon_set_property_sync);
  683. /**
  684. * extcon_get_property_capability() - Get the capability of property
  685. * of an external connector.
  686. * @edev: the extcon device that has the cable.
  687. * @id: the unique id of each external connector
  688. * in extcon enumeration.
  689. * @prop: the property id among enum extcon_property.
  690. *
  691. * Returns 1 if the property is available or 0 if not available.
  692. */
  693. int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id,
  694. unsigned int prop)
  695. {
  696. int index;
  697. if (!edev)
  698. return -EINVAL;
  699. /* Check whether the property is supported or not */
  700. if (!is_extcon_property_supported(id, prop))
  701. return -EINVAL;
  702. /* Find the cable index of external connector by using id */
  703. index = find_cable_index_by_id(edev, id);
  704. if (index < 0)
  705. return index;
  706. return is_extcon_property_capability(edev, id, index, prop);
  707. }
  708. EXPORT_SYMBOL_GPL(extcon_get_property_capability);
  709. /**
  710. * extcon_set_property_capability() - Set the capability of a property
  711. * of an external connector.
  712. * @edev: the extcon device that has the cable.
  713. * @id: the unique id of each external connector
  714. * in extcon enumeration.
  715. * @prop: the property id among enum extcon_property.
  716. *
  717. * This function set the capability of a property for an external connector
  718. * to mark the bit in capability bitmap which mean the available state of
  719. * a property.
  720. *
  721. * Returns 0 if success or error number if fail
  722. */
  723. int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id,
  724. unsigned int prop)
  725. {
  726. struct extcon_cable *cable;
  727. int index, type, ret = 0;
  728. if (!edev)
  729. return -EINVAL;
  730. /* Check whether the property is supported or not. */
  731. if (!is_extcon_property_supported(id, prop))
  732. return -EINVAL;
  733. /* Find the cable index of external connector by using id. */
  734. index = find_cable_index_by_id(edev, id);
  735. if (index < 0)
  736. return index;
  737. type = get_extcon_type(prop);
  738. if (type < 0)
  739. return type;
  740. cable = &edev->cables[index];
  741. switch (type) {
  742. case EXTCON_TYPE_USB:
  743. __set_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits);
  744. break;
  745. case EXTCON_TYPE_CHG:
  746. __set_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits);
  747. break;
  748. case EXTCON_TYPE_JACK:
  749. __set_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits);
  750. break;
  751. case EXTCON_TYPE_DISP:
  752. __set_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits);
  753. break;
  754. default:
  755. ret = -EINVAL;
  756. }
  757. return ret;
  758. }
  759. EXPORT_SYMBOL_GPL(extcon_set_property_capability);
  760. /**
  761. * extcon_get_extcon_dev() - Get the extcon device instance from the name
  762. * @extcon_name: The extcon name provided with extcon_dev_register()
  763. */
  764. struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
  765. {
  766. struct extcon_dev *sd;
  767. if (!extcon_name)
  768. return ERR_PTR(-EINVAL);
  769. mutex_lock(&extcon_dev_list_lock);
  770. list_for_each_entry(sd, &extcon_dev_list, entry) {
  771. if (!strcmp(sd->name, extcon_name))
  772. goto out;
  773. }
  774. sd = NULL;
  775. out:
  776. mutex_unlock(&extcon_dev_list_lock);
  777. return sd;
  778. }
  779. EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
  780. /**
  781. * extcon_register_notifier() - Register a notifiee to get notified by
  782. * any attach status changes from the extcon.
  783. * @edev: the extcon device that has the external connecotr.
  784. * @id: the unique id of each external connector in extcon enumeration.
  785. * @nb: a notifier block to be registered.
  786. *
  787. * Note that the second parameter given to the callback of nb (val) is
  788. * "old_state", not the current state. The current state can be retrieved
  789. * by looking at the third pameter (edev pointer)'s state value.
  790. */
  791. int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
  792. struct notifier_block *nb)
  793. {
  794. unsigned long flags;
  795. int ret, idx = -EINVAL;
  796. if (!edev || !nb)
  797. return -EINVAL;
  798. idx = find_cable_index_by_id(edev, id);
  799. if (idx < 0)
  800. return idx;
  801. spin_lock_irqsave(&edev->lock, flags);
  802. ret = raw_notifier_chain_register(&edev->nh[idx], nb);
  803. spin_unlock_irqrestore(&edev->lock, flags);
  804. return ret;
  805. }
  806. EXPORT_SYMBOL_GPL(extcon_register_notifier);
  807. /**
  808. * extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
  809. * @edev: the extcon device that has the external connecotr.
  810. * @id: the unique id of each external connector in extcon enumeration.
  811. * @nb: a notifier block to be registered.
  812. */
  813. int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
  814. struct notifier_block *nb)
  815. {
  816. unsigned long flags;
  817. int ret, idx;
  818. if (!edev || !nb)
  819. return -EINVAL;
  820. idx = find_cable_index_by_id(edev, id);
  821. if (idx < 0)
  822. return idx;
  823. spin_lock_irqsave(&edev->lock, flags);
  824. ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
  825. spin_unlock_irqrestore(&edev->lock, flags);
  826. return ret;
  827. }
  828. EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
  829. /**
  830. * extcon_register_notifier_all() - Register a notifier block for all connectors
  831. * @edev: the extcon device that has the external connector.
  832. * @nb: a notifier block to be registered.
  833. *
  834. * This function registers a notifier block in order to receive the state
  835. * change of all supported external connectors from extcon device.
  836. * And the second parameter given to the callback of nb (val) is
  837. * the current state and third parameter is the edev pointer.
  838. *
  839. * Returns 0 if success or error number if fail
  840. */
  841. int extcon_register_notifier_all(struct extcon_dev *edev,
  842. struct notifier_block *nb)
  843. {
  844. unsigned long flags;
  845. int ret;
  846. if (!edev || !nb)
  847. return -EINVAL;
  848. spin_lock_irqsave(&edev->lock, flags);
  849. ret = raw_notifier_chain_register(&edev->nh_all, nb);
  850. spin_unlock_irqrestore(&edev->lock, flags);
  851. return ret;
  852. }
  853. EXPORT_SYMBOL_GPL(extcon_register_notifier_all);
  854. /**
  855. * extcon_unregister_notifier_all() - Unregister a notifier block from extcon.
  856. * @edev: the extcon device that has the external connecotr.
  857. * @nb: a notifier block to be registered.
  858. *
  859. * Returns 0 if success or error number if fail
  860. */
  861. int extcon_unregister_notifier_all(struct extcon_dev *edev,
  862. struct notifier_block *nb)
  863. {
  864. unsigned long flags;
  865. int ret;
  866. if (!edev || !nb)
  867. return -EINVAL;
  868. spin_lock_irqsave(&edev->lock, flags);
  869. ret = raw_notifier_chain_unregister(&edev->nh_all, nb);
  870. spin_unlock_irqrestore(&edev->lock, flags);
  871. return ret;
  872. }
  873. EXPORT_SYMBOL_GPL(extcon_unregister_notifier_all);
  874. static struct attribute *extcon_attrs[] = {
  875. &dev_attr_state.attr,
  876. &dev_attr_name.attr,
  877. NULL,
  878. };
  879. ATTRIBUTE_GROUPS(extcon);
  880. static int create_extcon_class(void)
  881. {
  882. if (!extcon_class) {
  883. extcon_class = class_create(THIS_MODULE, "extcon");
  884. if (IS_ERR(extcon_class))
  885. return PTR_ERR(extcon_class);
  886. extcon_class->dev_groups = extcon_groups;
  887. }
  888. return 0;
  889. }
  890. static void extcon_dev_release(struct device *dev)
  891. {
  892. }
  893. static const char *muex_name = "mutually_exclusive";
  894. static void dummy_sysfs_dev_release(struct device *dev)
  895. {
  896. }
  897. /*
  898. * extcon_dev_allocate() - Allocate the memory of extcon device.
  899. * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
  900. * If supported_cable is NULL, cable name related APIs
  901. * are disabled.
  902. *
  903. * This function allocates the memory for extcon device without allocating
  904. * memory in each extcon provider driver and initialize default setting for
  905. * extcon device.
  906. *
  907. * Return the pointer of extcon device if success or ERR_PTR(err) if fail
  908. */
  909. struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
  910. {
  911. struct extcon_dev *edev;
  912. if (!supported_cable)
  913. return ERR_PTR(-EINVAL);
  914. edev = kzalloc(sizeof(*edev), GFP_KERNEL);
  915. if (!edev)
  916. return ERR_PTR(-ENOMEM);
  917. edev->max_supported = 0;
  918. edev->supported_cable = supported_cable;
  919. return edev;
  920. }
  921. /*
  922. * extcon_dev_free() - Free the memory of extcon device.
  923. * @edev: the extcon device to free
  924. */
  925. void extcon_dev_free(struct extcon_dev *edev)
  926. {
  927. kfree(edev);
  928. }
  929. EXPORT_SYMBOL_GPL(extcon_dev_free);
  930. /**
  931. * extcon_dev_register() - Register a new extcon device
  932. * @edev : the new extcon device (should be allocated before calling)
  933. *
  934. * Among the members of edev struct, please set the "user initializing data"
  935. * in any case and set the "optional callbacks" if required. However, please
  936. * do not set the values of "internal data", which are initialized by
  937. * this function.
  938. */
  939. int extcon_dev_register(struct extcon_dev *edev)
  940. {
  941. int ret, index = 0;
  942. static atomic_t edev_no = ATOMIC_INIT(-1);
  943. if (!extcon_class) {
  944. ret = create_extcon_class();
  945. if (ret < 0)
  946. return ret;
  947. }
  948. if (!edev || !edev->supported_cable)
  949. return -EINVAL;
  950. for (; edev->supported_cable[index] != EXTCON_NONE; index++);
  951. edev->max_supported = index;
  952. if (index > SUPPORTED_CABLE_MAX) {
  953. dev_err(&edev->dev,
  954. "exceed the maximum number of supported cables\n");
  955. return -EINVAL;
  956. }
  957. edev->dev.class = extcon_class;
  958. edev->dev.release = extcon_dev_release;
  959. edev->name = dev_name(edev->dev.parent);
  960. if (IS_ERR_OR_NULL(edev->name)) {
  961. dev_err(&edev->dev,
  962. "extcon device name is null\n");
  963. return -EINVAL;
  964. }
  965. dev_set_name(&edev->dev, "extcon%lu",
  966. (unsigned long)atomic_inc_return(&edev_no));
  967. if (edev->max_supported) {
  968. char buf[10];
  969. char *str;
  970. struct extcon_cable *cable;
  971. edev->cables = kzalloc(sizeof(struct extcon_cable) *
  972. edev->max_supported, GFP_KERNEL);
  973. if (!edev->cables) {
  974. ret = -ENOMEM;
  975. goto err_sysfs_alloc;
  976. }
  977. for (index = 0; index < edev->max_supported; index++) {
  978. cable = &edev->cables[index];
  979. snprintf(buf, 10, "cable.%d", index);
  980. str = kzalloc(sizeof(char) * (strlen(buf) + 1),
  981. GFP_KERNEL);
  982. if (!str) {
  983. for (index--; index >= 0; index--) {
  984. cable = &edev->cables[index];
  985. kfree(cable->attr_g.name);
  986. }
  987. ret = -ENOMEM;
  988. goto err_alloc_cables;
  989. }
  990. strcpy(str, buf);
  991. cable->edev = edev;
  992. cable->cable_index = index;
  993. cable->attrs[0] = &cable->attr_name.attr;
  994. cable->attrs[1] = &cable->attr_state.attr;
  995. cable->attrs[2] = NULL;
  996. cable->attr_g.name = str;
  997. cable->attr_g.attrs = cable->attrs;
  998. sysfs_attr_init(&cable->attr_name.attr);
  999. cable->attr_name.attr.name = "name";
  1000. cable->attr_name.attr.mode = 0444;
  1001. cable->attr_name.show = cable_name_show;
  1002. sysfs_attr_init(&cable->attr_state.attr);
  1003. cable->attr_state.attr.name = "state";
  1004. cable->attr_state.attr.mode = 0444;
  1005. cable->attr_state.show = cable_state_show;
  1006. }
  1007. }
  1008. if (edev->max_supported && edev->mutually_exclusive) {
  1009. char buf[80];
  1010. char *name;
  1011. /* Count the size of mutually_exclusive array */
  1012. for (index = 0; edev->mutually_exclusive[index]; index++)
  1013. ;
  1014. edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
  1015. (index + 1), GFP_KERNEL);
  1016. if (!edev->attrs_muex) {
  1017. ret = -ENOMEM;
  1018. goto err_muex;
  1019. }
  1020. edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
  1021. index, GFP_KERNEL);
  1022. if (!edev->d_attrs_muex) {
  1023. ret = -ENOMEM;
  1024. kfree(edev->attrs_muex);
  1025. goto err_muex;
  1026. }
  1027. for (index = 0; edev->mutually_exclusive[index]; index++) {
  1028. sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
  1029. name = kzalloc(sizeof(char) * (strlen(buf) + 1),
  1030. GFP_KERNEL);
  1031. if (!name) {
  1032. for (index--; index >= 0; index--) {
  1033. kfree(edev->d_attrs_muex[index].attr.
  1034. name);
  1035. }
  1036. kfree(edev->d_attrs_muex);
  1037. kfree(edev->attrs_muex);
  1038. ret = -ENOMEM;
  1039. goto err_muex;
  1040. }
  1041. strcpy(name, buf);
  1042. sysfs_attr_init(&edev->d_attrs_muex[index].attr);
  1043. edev->d_attrs_muex[index].attr.name = name;
  1044. edev->d_attrs_muex[index].attr.mode = 0000;
  1045. edev->attrs_muex[index] = &edev->d_attrs_muex[index]
  1046. .attr;
  1047. }
  1048. edev->attr_g_muex.name = muex_name;
  1049. edev->attr_g_muex.attrs = edev->attrs_muex;
  1050. }
  1051. if (edev->max_supported) {
  1052. edev->extcon_dev_type.groups =
  1053. kzalloc(sizeof(struct attribute_group *) *
  1054. (edev->max_supported + 2), GFP_KERNEL);
  1055. if (!edev->extcon_dev_type.groups) {
  1056. ret = -ENOMEM;
  1057. goto err_alloc_groups;
  1058. }
  1059. edev->extcon_dev_type.name = dev_name(&edev->dev);
  1060. edev->extcon_dev_type.release = dummy_sysfs_dev_release;
  1061. for (index = 0; index < edev->max_supported; index++)
  1062. edev->extcon_dev_type.groups[index] =
  1063. &edev->cables[index].attr_g;
  1064. if (edev->mutually_exclusive)
  1065. edev->extcon_dev_type.groups[index] =
  1066. &edev->attr_g_muex;
  1067. edev->dev.type = &edev->extcon_dev_type;
  1068. }
  1069. ret = device_register(&edev->dev);
  1070. if (ret) {
  1071. put_device(&edev->dev);
  1072. goto err_dev;
  1073. }
  1074. spin_lock_init(&edev->lock);
  1075. edev->nh = devm_kcalloc(&edev->dev, edev->max_supported,
  1076. sizeof(*edev->nh), GFP_KERNEL);
  1077. if (!edev->nh) {
  1078. ret = -ENOMEM;
  1079. goto err_dev;
  1080. }
  1081. for (index = 0; index < edev->max_supported; index++)
  1082. RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
  1083. RAW_INIT_NOTIFIER_HEAD(&edev->nh_all);
  1084. dev_set_drvdata(&edev->dev, edev);
  1085. edev->state = 0;
  1086. mutex_lock(&extcon_dev_list_lock);
  1087. list_add(&edev->entry, &extcon_dev_list);
  1088. mutex_unlock(&extcon_dev_list_lock);
  1089. return 0;
  1090. err_dev:
  1091. if (edev->max_supported)
  1092. kfree(edev->extcon_dev_type.groups);
  1093. err_alloc_groups:
  1094. if (edev->max_supported && edev->mutually_exclusive) {
  1095. for (index = 0; edev->mutually_exclusive[index]; index++)
  1096. kfree(edev->d_attrs_muex[index].attr.name);
  1097. kfree(edev->d_attrs_muex);
  1098. kfree(edev->attrs_muex);
  1099. }
  1100. err_muex:
  1101. for (index = 0; index < edev->max_supported; index++)
  1102. kfree(edev->cables[index].attr_g.name);
  1103. err_alloc_cables:
  1104. if (edev->max_supported)
  1105. kfree(edev->cables);
  1106. err_sysfs_alloc:
  1107. return ret;
  1108. }
  1109. EXPORT_SYMBOL_GPL(extcon_dev_register);
  1110. /**
  1111. * extcon_dev_unregister() - Unregister the extcon device.
  1112. * @edev: the extcon device instance to be unregistered.
  1113. *
  1114. * Note that this does not call kfree(edev) because edev was not allocated
  1115. * by this class.
  1116. */
  1117. void extcon_dev_unregister(struct extcon_dev *edev)
  1118. {
  1119. int index;
  1120. if (!edev)
  1121. return;
  1122. mutex_lock(&extcon_dev_list_lock);
  1123. list_del(&edev->entry);
  1124. mutex_unlock(&extcon_dev_list_lock);
  1125. if (IS_ERR_OR_NULL(get_device(&edev->dev))) {
  1126. dev_err(&edev->dev, "Failed to unregister extcon_dev (%s)\n",
  1127. dev_name(&edev->dev));
  1128. return;
  1129. }
  1130. device_unregister(&edev->dev);
  1131. if (edev->mutually_exclusive && edev->max_supported) {
  1132. for (index = 0; edev->mutually_exclusive[index];
  1133. index++)
  1134. kfree(edev->d_attrs_muex[index].attr.name);
  1135. kfree(edev->d_attrs_muex);
  1136. kfree(edev->attrs_muex);
  1137. }
  1138. for (index = 0; index < edev->max_supported; index++)
  1139. kfree(edev->cables[index].attr_g.name);
  1140. if (edev->max_supported) {
  1141. kfree(edev->extcon_dev_type.groups);
  1142. kfree(edev->cables);
  1143. }
  1144. put_device(&edev->dev);
  1145. }
  1146. EXPORT_SYMBOL_GPL(extcon_dev_unregister);
  1147. #ifdef CONFIG_OF
  1148. /*
  1149. * extcon_get_edev_by_phandle - Get the extcon device from devicetree
  1150. * @dev - instance to the given device
  1151. * @index - index into list of extcon_dev
  1152. *
  1153. * return the instance of extcon device
  1154. */
  1155. struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
  1156. {
  1157. struct device_node *node;
  1158. struct extcon_dev *edev;
  1159. if (!dev)
  1160. return ERR_PTR(-EINVAL);
  1161. if (!dev->of_node) {
  1162. dev_dbg(dev, "device does not have a device node entry\n");
  1163. return ERR_PTR(-EINVAL);
  1164. }
  1165. node = of_parse_phandle(dev->of_node, "extcon", index);
  1166. if (!node) {
  1167. dev_dbg(dev, "failed to get phandle in %pOF node\n",
  1168. dev->of_node);
  1169. return ERR_PTR(-ENODEV);
  1170. }
  1171. mutex_lock(&extcon_dev_list_lock);
  1172. list_for_each_entry(edev, &extcon_dev_list, entry) {
  1173. if (edev->dev.parent && edev->dev.parent->of_node == node) {
  1174. mutex_unlock(&extcon_dev_list_lock);
  1175. of_node_put(node);
  1176. return edev;
  1177. }
  1178. }
  1179. mutex_unlock(&extcon_dev_list_lock);
  1180. of_node_put(node);
  1181. return ERR_PTR(-EPROBE_DEFER);
  1182. }
  1183. #else
  1184. struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
  1185. {
  1186. return ERR_PTR(-ENOSYS);
  1187. }
  1188. #endif /* CONFIG_OF */
  1189. EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
  1190. /**
  1191. * extcon_get_edev_name() - Get the name of the extcon device.
  1192. * @edev: the extcon device
  1193. */
  1194. const char *extcon_get_edev_name(struct extcon_dev *edev)
  1195. {
  1196. return !edev ? NULL : edev->name;
  1197. }
  1198. static int __init extcon_class_init(void)
  1199. {
  1200. return create_extcon_class();
  1201. }
  1202. module_init(extcon_class_init);
  1203. static void __exit extcon_class_exit(void)
  1204. {
  1205. class_destroy(extcon_class);
  1206. }
  1207. module_exit(extcon_class_exit);
  1208. MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
  1209. MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
  1210. MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
  1211. MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
  1212. MODULE_DESCRIPTION("External connector (extcon) class driver");
  1213. MODULE_LICENSE("GPL");