summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/core.c')
-rw-r--r--drivers/pinctrl/core.c141
1 files changed, 109 insertions, 32 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index f424a57f0013..83254a95ef17 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -70,6 +70,7 @@ void pinctrl_provide_dummies(void)
{
pinctrl_dummy_state = true;
}
+EXPORT_SYMBOL_GPL(pinctrl_provide_dummies);
const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
{
@@ -220,6 +221,9 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
/* Set owner */
pindesc->pctldev = pctldev;
+#ifdef CONFIG_PINMUX
+ mutex_init(&pindesc->mux_lock);
+#endif
/* Copy basic pin info */
if (pin->name) {
@@ -1253,6 +1257,20 @@ static void pinctrl_link_add(struct pinctrl_dev *pctldev,
DL_FLAG_AUTOREMOVE_CONSUMER);
}
+static void pinctrl_cond_disable_mux_setting(struct pinctrl_state *state,
+ struct pinctrl_setting *target_setting)
+{
+ struct pinctrl_setting *setting;
+
+ list_for_each_entry(setting, &state->settings, node) {
+ if (target_setting && (&setting->node == &target_setting->node))
+ break;
+
+ if (setting->type == PIN_MAP_TYPE_MUX_GROUP)
+ pinmux_disable_setting(setting);
+ }
+}
+
/**
* pinctrl_commit_state() - select/activate/program a pinctrl state to HW
* @p: the pinctrl handle for the device that requests configuration
@@ -1260,7 +1278,7 @@ static void pinctrl_link_add(struct pinctrl_dev *pctldev,
*/
static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
{
- struct pinctrl_setting *setting, *setting2;
+ struct pinctrl_setting *setting;
struct pinctrl_state *old_state = READ_ONCE(p->state);
int ret;
@@ -1271,11 +1289,7 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
* still owned by the new state will be re-acquired by the call
* to pinmux_enable_setting() in the loop below.
*/
- list_for_each_entry(setting, &old_state->settings, node) {
- if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
- continue;
- pinmux_disable_setting(setting);
- }
+ pinctrl_cond_disable_mux_setting(old_state, NULL);
}
p->state = NULL;
@@ -1319,7 +1333,7 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
}
if (ret < 0) {
- goto unapply_new_state;
+ goto unapply_mux_setting;
}
/* Do not link hogs (circular dependency) */
@@ -1331,23 +1345,23 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state)
return 0;
+unapply_mux_setting:
+ pinctrl_cond_disable_mux_setting(state, NULL);
+ goto restore_old_state;
+
unapply_new_state:
dev_err(p->dev, "Error applying setting, reverse things back\n");
- list_for_each_entry(setting2, &state->settings, node) {
- if (&setting2->node == &setting->node)
- break;
- /*
- * All we can do here is pinmux_disable_setting.
- * That means that some pins are muxed differently now
- * than they were before applying the setting (We can't
- * "unmux a pin"!), but it's not a big deal since the pins
- * are free to be muxed by another apply_setting.
- */
- if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
- pinmux_disable_setting(setting2);
- }
+ /*
+ * All we can do here is pinmux_disable_setting.
+ * That means that some pins are muxed differently now
+ * than they were before applying the setting (We can't
+ * "unmux a pin"!), but it's not a big deal since the pins
+ * are free to be muxed by another apply_setting.
+ */
+ pinctrl_cond_disable_mux_setting(state, setting);
+restore_old_state:
/* There's no infinite recursive loop here because p->state is NULL */
if (old_state)
pinctrl_select_state(p, old_state);
@@ -1517,6 +1531,35 @@ void pinctrl_unregister_mappings(const struct pinctrl_map *map)
}
EXPORT_SYMBOL_GPL(pinctrl_unregister_mappings);
+static void devm_pinctrl_unregister_mappings(void *maps)
+{
+ pinctrl_unregister_mappings(maps);
+}
+
+/**
+ * devm_pinctrl_register_mappings() - Resource managed pinctrl_register_mappings()
+ * @dev: device for which mappings are registered
+ * @maps: the pincontrol mappings table to register. Note the pinctrl-core
+ * keeps a reference to the passed in maps, so they should _not_ be
+ * marked with __initdata.
+ * @num_maps: the number of maps in the mapping table
+ *
+ * Returns: 0 on success, or negative errno on failure.
+ */
+int devm_pinctrl_register_mappings(struct device *dev,
+ const struct pinctrl_map *maps,
+ unsigned int num_maps)
+{
+ int ret;
+
+ ret = pinctrl_register_mappings(maps, num_maps);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, devm_pinctrl_unregister_mappings, (void *)maps);
+}
+EXPORT_SYMBOL_GPL(devm_pinctrl_register_mappings);
+
/**
* pinctrl_force_sleep() - turn a given controller device into sleep state
* @pctldev: pin controller device
@@ -1614,6 +1657,19 @@ int pinctrl_pm_select_default_state(struct device *dev)
EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state);
/**
+ * pinctrl_pm_select_init_state() - select init pinctrl state for PM
+ * @dev: device to select init state for
+ */
+int pinctrl_pm_select_init_state(struct device *dev)
+{
+ if (!dev->pins)
+ return 0;
+
+ return pinctrl_select_bound_state(dev, dev->pins->init_state);
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_init_state);
+
+/**
* pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM
* @dev: device to select sleep state for
*/
@@ -1670,13 +1726,23 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
seq_printf(s, "pin %d (%s) ", pin, desc->name);
#ifdef CONFIG_GPIOLIB
+ gdev = NULL;
gpio_num = -1;
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
- if ((pin >= range->pin_base) &&
- (pin < (range->pin_base + range->npins))) {
- gpio_num = range->base + (pin - range->pin_base);
- break;
+ if (range->pins != NULL) {
+ for (int i = 0; i < range->npins; ++i) {
+ if (range->pins[i] == pin) {
+ gpio_num = range->base + i;
+ break;
+ }
+ }
+ } else if ((pin >= range->pin_base) &&
+ (pin < (range->pin_base + range->npins))) {
+ gpio_num =
+ range->base + (pin - range->pin_base);
}
+ if (gpio_num != -1)
+ break;
}
if (gpio_num >= 0)
/*
@@ -1961,7 +2027,7 @@ static void pinctrl_remove_device_debugfs(struct pinctrl_dev *pctldev)
static void pinctrl_init_debugfs(void)
{
debugfs_root = debugfs_create_dir("pinctrl", NULL);
- if (IS_ERR(debugfs_root) || !debugfs_root) {
+ if (IS_ERR(debugfs_root)) {
pr_warn("failed to create debugfs directory\n");
debugfs_root = NULL;
return;
@@ -2010,7 +2076,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
* @driver_data: private pin controller data for this pin controller
*/
static struct pinctrl_dev *
-pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
+pinctrl_init_controller(const struct pinctrl_desc *pctldesc, struct device *dev,
void *driver_data)
{
struct pinctrl_dev *pctldev;
@@ -2080,6 +2146,15 @@ out_err:
return ERR_PTR(ret);
}
+static void pinctrl_uninit_controller(struct pinctrl_dev *pctldev,
+ const struct pinctrl_desc *pctldesc)
+{
+ pinctrl_free_pindescs(pctldev, pctldesc->pins,
+ pctldesc->npins);
+ mutex_destroy(&pctldev->mutex);
+ kfree(pctldev);
+}
+
static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
{
pctldev->p = create_pinctrl(pctldev->dev, pctldev);
@@ -2149,7 +2224,7 @@ EXPORT_SYMBOL_GPL(pinctrl_enable);
* struct pinctrl_dev handle. To avoid issues later on, please use the
* new pinctrl_register_and_init() below instead.
*/
-struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
+struct pinctrl_dev *pinctrl_register(const struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data)
{
struct pinctrl_dev *pctldev;
@@ -2160,8 +2235,10 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
return pctldev;
error = pinctrl_enable(pctldev);
- if (error)
+ if (error) {
+ pinctrl_uninit_controller(pctldev, pctldesc);
return ERR_PTR(error);
+ }
return pctldev;
}
@@ -2177,7 +2254,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
* Note that pinctrl_enable() still needs to be manually called after
* this once the driver is ready.
*/
-int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
+int pinctrl_register_and_init(const struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data,
struct pinctrl_dev **pctldev)
{
@@ -2268,7 +2345,7 @@ static int devm_pinctrl_dev_match(struct device *dev, void *res, void *data)
* The pinctrl device will be automatically released when the device is unbound.
*/
struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
- struct pinctrl_desc *pctldesc,
+ const struct pinctrl_desc *pctldesc,
void *driver_data)
{
struct pinctrl_dev **ptr, *pctldev;
@@ -2302,7 +2379,7 @@ EXPORT_SYMBOL_GPL(devm_pinctrl_register);
* The pinctrl device will be automatically released when the device is unbound.
*/
int devm_pinctrl_register_and_init(struct device *dev,
- struct pinctrl_desc *pctldesc,
+ const struct pinctrl_desc *pctldesc,
void *driver_data,
struct pinctrl_dev **pctldev)
{
@@ -2340,7 +2417,7 @@ EXPORT_SYMBOL_GPL(devm_pinctrl_unregister);
static int __init pinctrl_init(void)
{
- pr_info("initialized pinctrl subsystem\n");
+ pr_debug("initialized pinctrl subsystem\n");
pinctrl_init_debugfs();
return 0;
}