// SPDX-License-Identifier: GPL-2.0-only /* * drivers/extcon/extcon.c - External Connector (extcon) framework. * * Copyright (C) 2015 Samsung Electronics * Author: Chanwoo Choi <[email protected]> * * Copyright (C) 2012 Samsung Electronics * Author: Donggeun Kim <[email protected]> * Author: MyungJoo Ham <[email protected]> * * based on android/drivers/switch/switch_class.c * Copyright (C) 2008 Google, Inc. * Author: Mike Lockwood <[email protected]> */ #include <linux/module.h> #include <linux/types.h> #include <linux/idr.h> #include <linux/init.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/err.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/sysfs.h> #include "extcon.h" #define SUPPORTED_CABLE_MAX … static const struct __extcon_info { … } extcon_info[] = …; /** * struct extcon_cable - An internal data for an external connector. * @edev: the extcon device * @cable_index: the index of this cable in the edev * @attr_g: the attribute group for the cable * @attr_name: "name" sysfs entry * @attr_state: "state" sysfs entry * @attrs: the array pointing to attr_name and attr_state for attr_g * @usb_propval: the array of USB connector properties * @chg_propval: the array of charger connector properties * @jack_propval: the array of jack connector properties * @disp_propval: the array of display connector properties * @usb_bits: the bit array of the USB connector property capabilities * @chg_bits: the bit array of the charger connector property capabilities * @jack_bits: the bit array of the jack connector property capabilities * @disp_bits: the bit array of the display connector property capabilities */ struct extcon_cable { … }; static struct class *extcon_class; static DEFINE_IDA(extcon_dev_ids); static LIST_HEAD(extcon_dev_list); static DEFINE_MUTEX(extcon_dev_list_lock); static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) { … } static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id) { … } static int get_extcon_type(unsigned int prop) { … } static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index) { … } static bool is_extcon_changed(struct extcon_dev *edev, int index, bool new_state) { … } static bool is_extcon_property_supported(unsigned int id, unsigned int prop) { … } static int is_extcon_property_capability(struct extcon_dev *edev, unsigned int id, int index,unsigned int prop) { … } static void init_property(struct extcon_dev *edev, unsigned int id, int index) { … } static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static DEVICE_ATTR_RO(state); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static DEVICE_ATTR_RO(name); static ssize_t cable_name_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static ssize_t cable_state_show(struct device *dev, struct device_attribute *attr, char *buf) { … } /** * extcon_sync() - Synchronize the state for an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * * Note that this function send a notification in order to synchronize * the state and property of an external connector. * * Returns 0 if success or error number if fail. */ int extcon_sync(struct extcon_dev *edev, unsigned int id) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_get_state() - Get the state of an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * * Returns 0 if success or error number if fail. */ int extcon_get_state(struct extcon_dev *edev, const unsigned int id) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_set_state() - Set the state of an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * @state: the new state of an external connector. * the default semantics is true: attached / false: detached. * * Note that this function set the state of an external connector without * a notification. To synchronize the state of an external connector, * have to use extcon_set_state_sync() and extcon_sync(). * * Returns 0 if success or error number if fail. */ int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool state) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_set_state_sync() - Set the state of an external connector with sync. * @edev: the extcon device * @id: the unique id indicating an external connector * @state: the new state of external connector. * the default semantics is true: attached / false: detached. * * Note that this function set the state of external connector * and synchronize the state by sending a notification. * * Returns 0 if success or error number if fail. */ int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, bool state) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_get_property() - Get the property value of an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * @prop: the property id indicating an extcon property * @prop_val: the pointer which store the value of extcon property * * Note that when getting the property value of external connector, * the external connector should be attached. If detached state, function * return 0 without property value. Also, the each property should be * included in the list of supported properties according to extcon type. * * Returns 0 if success or error number if fail. */ int extcon_get_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value *prop_val) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_set_property() - Set the property value of an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * @prop: the property id indicating an extcon property * @prop_val: the pointer including the new value of extcon property * * Note that each property should be included in the list of supported * properties according to the extcon type. * * Returns 0 if success or error number if fail. */ int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_set_property_sync() - Set property of an external connector with sync. * @edev: the extcon device * @id: the unique id indicating an external connector * @prop: the property id indicating an extcon property * @prop_val: the pointer including the new value of extcon property * * Note that when setting the property value of external connector, * the external connector should be attached. The each property should * be included in the list of supported properties according to extcon type. * * Returns 0 if success or error number if fail. */ int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_get_property_capability() - Get the capability of the property * for an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * @prop: the property id indicating an extcon property * * Returns 1 if the property is available or 0 if not available. */ int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_set_property_capability() - Set the capability of the property * for an external connector. * @edev: the extcon device * @id: the unique id indicating an external connector * @prop: the property id indicating an extcon property * * Note that this function set the capability of the property * for an external connector in order to mark the bit in capability * bitmap which mean the available state of the property. * * Returns 0 if success or error number if fail. */ int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_get_extcon_dev() - Get the extcon device instance from the name. * @extcon_name: the extcon name provided with extcon_dev_register() * * Return the pointer of extcon device if success or ERR_PTR(err) if fail. * NOTE: This function returns -EPROBE_DEFER so it may only be called from * probe() functions. */ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_register_notifier() - Register a notifier block to get notified by * any state changes from the extcon. * @edev: the extcon device * @id: the unique id indicating an external connector * @nb: a notifier block to be registered * * Note that the second parameter given to the callback of nb (val) is * the current state of an external connector and the third pameter * is the pointer of extcon device. * * Returns 0 if success or error number if fail. */ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_unregister_notifier() - Unregister a notifier block from the extcon. * @edev: the extcon device * @id: the unique id indicating an external connector * @nb: a notifier block to be registered * * Returns 0 if success or error number if fail. */ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_register_notifier_all() - Register a notifier block for all connectors. * @edev: the extcon device * @nb: a notifier block to be registered * * Note that this function registers a notifier block in order to receive * the state change of all supported external connectors from extcon device. * And the second parameter given to the callback of nb (val) is * the current state and the third pameter is the pointer of extcon device. * * Returns 0 if success or error number if fail. */ int extcon_register_notifier_all(struct extcon_dev *edev, struct notifier_block *nb) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_unregister_notifier_all() - Unregister a notifier block from extcon. * @edev: the extcon device * @nb: a notifier block to be registered * * Returns 0 if success or error number if fail. */ int extcon_unregister_notifier_all(struct extcon_dev *edev, struct notifier_block *nb) { … } EXPORT_SYMBOL_GPL(…); static struct attribute *extcon_attrs[] = …; ATTRIBUTE_GROUPS(…); static int create_extcon_class(void) { … } static void extcon_dev_release(struct device *dev) { … } static const char *muex_name = …; static void dummy_sysfs_dev_release(struct device *dev) { … } /* * extcon_dev_allocate() - Allocate the memory of extcon device. * @supported_cable: the array of the supported external connectors * ending with EXTCON_NONE. * * Note that this function allocates the memory for extcon device * and initialize default setting for the extcon device. * * Returns the pointer memory of allocated extcon_dev if success * or ERR_PTR(err) if fail. */ struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable) { … } /* * extcon_dev_free() - Free the memory of extcon device. * @edev: the extcon device */ void extcon_dev_free(struct extcon_dev *edev) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_alloc_cables() - alloc the cables for extcon device * @edev: extcon device which has cables * * Returns 0 if success or error number if fail. */ static int extcon_alloc_cables(struct extcon_dev *edev) { … } /** * extcon_alloc_muex() - alloc the mutual exclusive for extcon device * @edev: extcon device * * Returns 0 if success or error number if fail. */ static int extcon_alloc_muex(struct extcon_dev *edev) { … } /** * extcon_alloc_groups() - alloc the groups for extcon device * @edev: extcon device * * Returns 0 if success or error number if fail. */ static int extcon_alloc_groups(struct extcon_dev *edev) { … } /** * extcon_dev_register() - Register an new extcon device * @edev: the extcon device to be registered * * Among the members of edev struct, please set the "user initializing data" * do not set the values of "internal data", which are initialized by * this function. * * Note that before calling this funciton, have to allocate the memory * of an extcon device by using the extcon_dev_allocate(). And the extcon * dev should include the supported_cable information. * * Returns 0 if success or error number if fail. */ int extcon_dev_register(struct extcon_dev *edev) { … } EXPORT_SYMBOL_GPL(…); /** * extcon_dev_unregister() - Unregister the extcon device. * @edev: the extcon device to be unregistered. * * Note that this does not call kfree(edev) because edev was not allocated * by this class. */ void extcon_dev_unregister(struct extcon_dev *edev) { … } EXPORT_SYMBOL_GPL(…); #ifdef CONFIG_OF /* * extcon_find_edev_by_node - Find the extcon device from devicetree. * @node : OF node identifying edev * * Return the pointer of extcon device if success or ERR_PTR(err) if fail. */ struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) { … } /* * extcon_get_edev_by_phandle - Get the extcon device from devicetree. * @dev : the instance to the given device * @index : the index into list of extcon_dev * * Return the pointer of extcon device if success or ERR_PTR(err) if fail. */ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { … } #else struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) { return ERR_PTR(-ENOSYS); } struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { return ERR_PTR(-ENOSYS); } #endif /* CONFIG_OF */ EXPORT_SYMBOL_GPL(…); EXPORT_SYMBOL_GPL(…); /** * extcon_get_edev_name() - Get the name of the extcon device. * @edev: the extcon device */ const char *extcon_get_edev_name(struct extcon_dev *edev) { … } EXPORT_SYMBOL_GPL(…); static int __init extcon_class_init(void) { … } module_init(…) …; static void __exit extcon_class_exit(void) { … } module_exit(extcon_class_exit); MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;