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