extcon.h 10.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 *  External connector (extcon) class driver
 *
 * Copyright (C) 2012 Samsung Electronics
 * Author: Donggeun Kim <dg77.kim@samsung.com>
 * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
 *
 * based on switch class driver
 * Copyright (C) 2008 Google, Inc.
 * Author: Mike Lockwood <lockwood@android.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
*/

#ifndef __LINUX_EXTCON_H__
#define __LINUX_EXTCON_H__

26
#include <linux/device.h>
27
#include <linux/notifier.h>
28
#include <linux/sysfs.h>
29 30 31 32 33 34

#define SUPPORTED_CABLE_MAX	32
#define CABLE_NAME_MAX		30

/*
 * The standard cable name is to help support general notifier
P
Peter Meerwald 已提交
35
 * and notifiee device drivers to share the common names.
36 37 38
 * Please use standard cable names unless your notifier device has
 * a very unique and abnormal cable or
 * the cable type is supposed to be used with only one unique
P
Peter Meerwald 已提交
39
 * pair of notifier/notifiee devices.
40 41 42 43 44 45
 *
 * Please add any other "standard" cables used with extcon dev.
 *
 * You may add a dot and number to specify version or specification
 * of the specific cable if it is required. (e.g., "Fast-charger.18"
 * and "Fast-charger.10" for 1.8A and 1.0A chargers)
P
Peter Meerwald 已提交
46 47
 * However, the notifiee and notifier should be able to handle such
 * string and if the notifiee can negotiate the protocol or identify,
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 * you don't need such convention. This convention is helpful when
 * notifier can distinguish but notifiee cannot.
 */
enum extcon_cable_name {
	EXTCON_USB = 0,
	EXTCON_USB_HOST,
	EXTCON_TA, /* Travel Adaptor */
	EXTCON_FAST_CHARGER,
	EXTCON_SLOW_CHARGER,
	EXTCON_CHARGE_DOWNSTREAM, /* Charging an external device */
	EXTCON_HDMI,
	EXTCON_MHL,
	EXTCON_DVI,
	EXTCON_VGA,
	EXTCON_DOCK,
	EXTCON_LINE_IN,
	EXTCON_LINE_OUT,
	EXTCON_MIC_IN,
	EXTCON_HEADPHONE_OUT,
	EXTCON_SPDIF_IN,
	EXTCON_SPDIF_OUT,
	EXTCON_VIDEO_IN,
	EXTCON_VIDEO_OUT,
71
	EXTCON_MECHANICAL,
72
};
73
extern const char extcon_cable_name[][CABLE_NAME_MAX + 1];
74 75 76

struct extcon_cable;

77 78
/**
 * struct extcon_dev - An extcon device represents one external connector.
M
MyungJoo Ham 已提交
79
 * @name:	The name of this extcon device. Parent device name is used
80
 *		if NULL.
M
MyungJoo Ham 已提交
81
 * @supported_cable:	Array of supported cable names ending with NULL.
82 83
 *			If supported_cable is NULL, cable name related APIs
 *			are disabled.
M
MyungJoo Ham 已提交
84
 * @mutually_exclusive:	Array of mutually exclusive set of cables that cannot
85 86 87 88 89 90 91
 *			be attached simultaneously. The array should be
 *			ending with NULL or be NULL (no mutually exclusive
 *			cables). For example, if it is { 0x7, 0x30, 0}, then,
 *			{0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
 *			be attached simulataneously. {0x7, 0} is equivalent to
 *			{0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
 *			can be no simultaneous connections.
M
MyungJoo Ham 已提交
92
 * @print_name:	An optional callback to override the method to print the
93
 *		name of the extcon device.
M
MyungJoo Ham 已提交
94
 * @print_state:	An optional callback to override the method to print the
95
 *		status of the extcon device.
M
MyungJoo Ham 已提交
96 97
 * @dev:	Device of this extcon. Do not provide at register-time.
 * @state:	Attach/detach state of this extcon. Do not provide at
98
 *		register-time
M
MyungJoo Ham 已提交
99 100
 * @nh:	Notifier for the state change events from this extcon
 * @entry:	To support list of extcon devices so that users can search
101
 *		for extcon devices based on the extcon name.
M
MyungJoo Ham 已提交
102 103 104
 * @lock:
 * @max_supported:	Internal value to store the number of cables.
 * @extcon_dev_type:	Device_type struct to provide attribute_groups
105
 *			customized for each extcon device.
M
MyungJoo Ham 已提交
106
 * @cables:	Sysfs subdirectories. Each represents one cable.
107 108 109 110 111 112 113 114 115
 *
 * In most cases, users only need to provide "User initializing data" of
 * this struct when registering an extcon. In some exceptional cases,
 * optional callbacks may be needed. However, the values in "internal data"
 * are overwritten by register function.
 */
struct extcon_dev {
	/* --- Optional user initializing data --- */
	const char	*name;
116
	const char **supported_cable;
117
	const u32	*mutually_exclusive;
118 119 120 121 122 123 124 125

	/* --- Optional callbacks to override class functions --- */
	ssize_t	(*print_name)(struct extcon_dev *edev, char *buf);
	ssize_t	(*print_state)(struct extcon_dev *edev, char *buf);

	/* --- Internal data. Please do not set. --- */
	struct device	*dev;
	u32		state;
126 127
	struct raw_notifier_head nh;
	struct list_head entry;
128 129 130 131 132 133
	spinlock_t lock; /* could be called by irq handler */
	int max_supported;

	/* /sys/class/extcon/.../cable.n/... */
	struct device_type extcon_dev_type;
	struct extcon_cable *cables;
134 135 136 137
	/* /sys/class/extcon/.../mutually_exclusive/... */
	struct attribute_group attr_g_muex;
	struct attribute **attrs_muex;
	struct device_attribute *d_attrs_muex;
138 139 140 141
};

/**
 * struct extcon_cable	- An internal data for each cable of extcon device.
M
MyungJoo Ham 已提交
142 143 144 145 146 147
 * @edev:	The extcon device
 * @cable_index:	Index of this cable in the edev
 * @attr_g:	Attribute group for the cable
 * @attr_name:	"name" sysfs entry
 * @attr_state:	"state" sysfs entry
 * @attrs:	Array pointing to attr_name and attr_state for attr_g
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
 */
struct extcon_cable {
	struct extcon_dev *edev;
	int cable_index;

	struct attribute_group attr_g;
	struct device_attribute attr_name;
	struct device_attribute attr_state;

	struct attribute *attrs[3]; /* to be fed to attr_g.attrs */
};

/**
 * struct extcon_specific_cable_nb - An internal data for
 *				extcon_register_interest().
M
MyungJoo Ham 已提交
163 164 165 166 167
 * @internal_nb:	a notifier block bridging extcon notifier and cable notifier.
 * @user_nb:	user provided notifier block for events from a specific cable.
 * @cable_index:	the target cable.
 * @edev:	the target extcon device.
 * @previous_value:	the saved previous event value.
168 169 170 171 172 173 174
 */
struct extcon_specific_cable_nb {
	struct notifier_block internal_nb;
	struct notifier_block *user_nb;
	int cable_index;
	struct extcon_dev *edev;
	unsigned long previous_value;
175 176 177
};

#if IS_ENABLED(CONFIG_EXTCON)
178 179 180 181 182

/*
 * Following APIs are for notifiers or configurations.
 * Notifiers are the external port and connection devices.
 */
183 184
extern int extcon_dev_register(struct extcon_dev *edev, struct device *dev);
extern void extcon_dev_unregister(struct extcon_dev *edev);
185
extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
186

187 188 189 190 191 192
/*
 * get/set/update_state access the 32b encoded state value, which represents
 * states of all possible cables of the multistate port. For example, if one
 * calls extcon_set_state(edev, 0x7), it may mean that all the three cables
 * are attached to the port.
 */
193 194 195 196 197
static inline u32 extcon_get_state(struct extcon_dev *edev)
{
	return edev->state;
}

198 199
extern int extcon_set_state(struct extcon_dev *edev, u32 state);
extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state);
200 201 202 203

/*
 * get/set_cable_state access each bit of the 32b encoded state value.
 * They are used to access the status of each cable based on the cable_name
P
Peter Meerwald 已提交
204
 * or cable_index, which is retrieved by extcon_find_cable_index
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
 */
extern int extcon_find_cable_index(struct extcon_dev *sdev,
				   const char *cable_name);
extern int extcon_get_cable_state_(struct extcon_dev *edev, int cable_index);
extern int extcon_set_cable_state_(struct extcon_dev *edev, int cable_index,
				   bool cable_state);

extern int extcon_get_cable_state(struct extcon_dev *edev,
				  const char *cable_name);
extern int extcon_set_cable_state(struct extcon_dev *edev,
				  const char *cable_name, bool cable_state);

/*
 * Following APIs are for notifiees (those who want to be notified)
 * to register a callback for events from a specific cable of the extcon.
 * Notifiees are the connected device drivers wanting to get notified by
 * a specific external port of a connection device.
 */
extern int extcon_register_interest(struct extcon_specific_cable_nb *obj,
				    const char *extcon_name,
				    const char *cable_name,
				    struct notifier_block *nb);
extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb);
228 229 230

/*
 * Following APIs are to monitor every action of a notifier.
P
Peter Meerwald 已提交
231
 * Registrar gets notified for every external port of a connection device.
232
 * Probably this could be used to debug an action of notifier; however,
P
Peter Meerwald 已提交
233
 * we do not recommend to use this for normal 'notifiee' device drivers who
234
 * want to be notified by a specific external port of the notifier.
235 236 237 238 239
 */
extern int extcon_register_notifier(struct extcon_dev *edev,
				    struct notifier_block *nb);
extern int extcon_unregister_notifier(struct extcon_dev *edev,
				      struct notifier_block *nb);
240 241 242 243 244 245 246 247 248 249 250 251 252 253
#else /* CONFIG_EXTCON */
static inline int extcon_dev_register(struct extcon_dev *edev,
				      struct device *dev)
{
	return 0;
}

static inline void extcon_dev_unregister(struct extcon_dev *edev) { }

static inline u32 extcon_get_state(struct extcon_dev *edev)
{
	return 0;
}

254 255 256 257
static inline int extcon_set_state(struct extcon_dev *edev, u32 state)
{
	return 0;
}
258

259
static inline int extcon_update_state(struct extcon_dev *edev, u32 mask,
260
				       u32 state)
261 262 263
{
	return 0;
}
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

static inline int extcon_find_cable_index(struct extcon_dev *edev,
					  const char *cable_name)
{
	return 0;
}

static inline int extcon_get_cable_state_(struct extcon_dev *edev,
					  int cable_index)
{
	return 0;
}

static inline int extcon_set_cable_state_(struct extcon_dev *edev,
					  int cable_index, bool cable_state)
{
	return 0;
}

static inline int extcon_get_cable_state(struct extcon_dev *edev,
			const char *cable_name)
{
	return 0;
}

static inline int extcon_set_cable_state(struct extcon_dev *edev,
			const char *cable_name, int state)
{
	return 0;
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
{
	return NULL;
}

static inline int extcon_register_notifier(struct extcon_dev *edev,
					   struct notifier_block *nb)
{
	return 0;
}

static inline int extcon_unregister_notifier(struct extcon_dev *edev,
					     struct notifier_block *nb)
{
	return 0;
}

312 313 314 315 316 317 318 319 320 321 322 323 324
static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj,
					   const char *extcon_name,
					   const char *cable_name,
					   struct notifier_block *nb)
{
	return 0;
}

static inline int extcon_unregister_interest(struct extcon_specific_cable_nb
						    *obj)
{
	return 0;
}
325 326
#endif /* CONFIG_EXTCON */
#endif /* __LINUX_EXTCON_H__ */