0e1507c845
Some accessory detection mechanisms are able to detect that something is physically present in the socket separately to identifying what is present in the socket. This information can be useful to applications, for example allowing them to indicate that a potentially broken accessory is present, so provide a standard way to report it to userspace. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
324 lines
10 KiB
C
324 lines
10 KiB
C
/*
|
|
* 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__
|
|
|
|
#include <linux/notifier.h>
|
|
|
|
#define SUPPORTED_CABLE_MAX 32
|
|
#define CABLE_NAME_MAX 30
|
|
|
|
/*
|
|
* The standard cable name is to help support general notifier
|
|
* and notifee device drivers to share the common names.
|
|
* 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
|
|
* pair of notifier/notifee devices.
|
|
*
|
|
* 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)
|
|
* However, the notifee and notifier should be able to handle such
|
|
* string and if the notifee can negotiate the protocol or idenify,
|
|
* 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,
|
|
EXTCON_MECHANICAL,
|
|
};
|
|
extern const char *extcon_cable_name[];
|
|
|
|
struct extcon_cable;
|
|
|
|
/**
|
|
* struct extcon_dev - An extcon device represents one external connector.
|
|
* @name The name of this extcon device. Parent device name is used
|
|
* if NULL.
|
|
* @supported_cable Array of supported cable name ending with NULL.
|
|
* If supported_cable is NULL, cable name related APIs
|
|
* are disabled.
|
|
* @mutually_exclusive Array of mutually exclusive set of cables that cannot
|
|
* 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.
|
|
* @print_name An optional callback to override the method to print the
|
|
* name of the extcon device.
|
|
* @print_state An optional callback to override the method to print the
|
|
* status of the extcon device.
|
|
* @dev Device of this extcon. Do not provide at register-time.
|
|
* @state Attach/detach state of this extcon. Do not provide at
|
|
* register-time
|
|
* @nh Notifier for the state change events from this extcon
|
|
* @entry To support list of extcon devices so that uses can search
|
|
* for extcon devices based on the extcon name.
|
|
* @lock
|
|
* @max_supported Internal value to store the number of cables.
|
|
* @extcon_dev_type Device_type struct to provide attribute_groups
|
|
* customized for each extcon device.
|
|
* @cables Sysfs subdirectories. Each represents one cable.
|
|
*
|
|
* 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;
|
|
const char **supported_cable;
|
|
const u32 *mutually_exclusive;
|
|
|
|
/* --- 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;
|
|
struct raw_notifier_head nh;
|
|
struct list_head entry;
|
|
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;
|
|
/* /sys/class/extcon/.../mutually_exclusive/... */
|
|
struct attribute_group attr_g_muex;
|
|
struct attribute **attrs_muex;
|
|
struct device_attribute *d_attrs_muex;
|
|
};
|
|
|
|
/**
|
|
* struct extcon_cable - An internal data for each cable of extcon device.
|
|
* @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
|
|
*/
|
|
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().
|
|
* @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.
|
|
*/
|
|
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;
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_EXTCON)
|
|
|
|
/*
|
|
* Following APIs are for notifiers or configurations.
|
|
* Notifiers are the external port and connection devices.
|
|
*/
|
|
extern int extcon_dev_register(struct extcon_dev *edev, struct device *dev);
|
|
extern void extcon_dev_unregister(struct extcon_dev *edev);
|
|
extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
static inline u32 extcon_get_state(struct extcon_dev *edev)
|
|
{
|
|
return edev->state;
|
|
}
|
|
|
|
extern int extcon_set_state(struct extcon_dev *edev, u32 state);
|
|
extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state);
|
|
|
|
/*
|
|
* 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
|
|
* or cable_index, which is retrived by extcon_find_cable_index
|
|
*/
|
|
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);
|
|
|
|
/*
|
|
* Following APIs are to monitor every action of a notifier.
|
|
* Registerer gets notified for every external port of a connection device.
|
|
* Probably this could be used to debug an action of notifier; however,
|
|
* we do not recommend to use this at normal 'notifiee' device drivers who
|
|
* want to be notified by a specific external port of the notifier.
|
|
*/
|
|
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);
|
|
#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;
|
|
}
|
|
|
|
static inline int extcon_set_state(struct extcon_dev *edev, u32 state)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int extcon_update_state(struct extcon_dev *edev, u32 mask,
|
|
u32 state)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
#endif /* CONFIG_EXTCON */
|
|
#endif /* __LINUX_EXTCON_H__ */
|