Skip to content

Commit

Permalink
pinctrl: core device tree mapping table parsing support
Browse files Browse the repository at this point in the history
During pinctrl_get(), if the client device has a device tree node, look
for the common pinctrl properties there. If found, parse the referenced
device tree nodes, with the help of the pinctrl drivers, and generate
mapping table entries from them.

During pinctrl_put(), free any results of device tree parsing.

Acked-by: Dong Aisheng <[email protected]>
Signed-off-by: Stephen Warren <[email protected]>
Signed-off-by: Linus Walleij <[email protected]>
  • Loading branch information
swarren authored and linusw committed Apr 18, 2012
1 parent d26bc49 commit 57291ce
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 18 deletions.
1 change: 1 addition & 0 deletions drivers/pinctrl/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
obj-$(CONFIG_PINCTRL) += core.o
obj-$(CONFIG_PINMUX) += pinmux.o
obj-$(CONFIG_PINCONF) += pinconf.o
obj-$(CONFIG_OF) += devicetree.o
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
Expand Down
72 changes: 55 additions & 17 deletions drivers/pinctrl/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/machine.h>
#include "core.h"
#include "devicetree.h"
#include "pinmux.h"
#include "pinconf.h"

Expand All @@ -45,7 +46,7 @@ struct pinctrl_maps {
DEFINE_MUTEX(pinctrl_mutex);

/* Global list of pin control devices (struct pinctrl_dev) */
static LIST_HEAD(pinctrldev_list);
LIST_HEAD(pinctrldev_list);

/* List of pin controller handles (struct pinctrl) */
static LIST_HEAD(pinctrl_list);
Expand Down Expand Up @@ -579,6 +580,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
}
p->dev = dev;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);

ret = pinctrl_dt_to_map(p);
if (ret < 0) {
kfree(p);
return ERR_PTR(ret);
}

devname = dev_name(dev);

Expand Down Expand Up @@ -662,6 +670,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
kfree(state);
}

pinctrl_dt_free_maps(p);

if (inlist)
list_del(&p->node);
kfree(p);
Expand Down Expand Up @@ -787,15 +797,8 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
}
EXPORT_SYMBOL_GPL(pinctrl_select_state);

/**
* pinctrl_register_mappings() - register a set of pin controller mappings
* @maps: the pincontrol mappings table to register. This should probably be
* marked with __initdata so it can be discarded after boot. This
* function will perform a shallow copy for the mapping entries.
* @num_maps: the number of maps in the mapping table
*/
int pinctrl_register_mappings(struct pinctrl_map const *maps,
unsigned num_maps)
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup, bool locked)
{
int i, ret;
struct pinctrl_maps *maps_node;
Expand Down Expand Up @@ -851,20 +854,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
}

maps_node->num_maps = num_maps;
maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
if (!maps_node->maps) {
pr_err("failed to duplicate mapping table\n");
kfree(maps_node);
return -ENOMEM;
if (dup) {
maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
GFP_KERNEL);
if (!maps_node->maps) {
pr_err("failed to duplicate mapping table\n");
kfree(maps_node);
return -ENOMEM;
}
} else {
maps_node->maps = maps;
}

mutex_lock(&pinctrl_mutex);
if (!locked)
mutex_lock(&pinctrl_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps);
mutex_unlock(&pinctrl_mutex);
if (!locked)
mutex_unlock(&pinctrl_mutex);

return 0;
}

/**
* pinctrl_register_mappings() - register a set of pin controller mappings
* @maps: the pincontrol mappings table to register. This should probably be
* marked with __initdata so it can be discarded after boot. This
* function will perform a shallow copy for the mapping entries.
* @num_maps: the number of maps in the mapping table
*/
int pinctrl_register_mappings(struct pinctrl_map const *maps,
unsigned num_maps)
{
return pinctrl_register_map(maps, num_maps, true, false);
}

void pinctrl_unregister_map(struct pinctrl_map const *map)
{
struct pinctrl_maps *maps_node;

list_for_each_entry(maps_node, &pinctrl_maps, node) {
if (maps_node->maps == map) {
list_del(&maps_node->node);
return;
}
}
}

#ifdef CONFIG_DEBUG_FS

static int pinctrl_pins_show(struct seq_file *s, void *what)
Expand Down Expand Up @@ -1231,6 +1266,9 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
!ops->get_group_pins)
return -EINVAL;

if (ops->dt_node_to_map && !ops->dt_free_map)
return -EINVAL;

return 0;
}

Expand Down
11 changes: 10 additions & 1 deletion drivers/pinctrl/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,15 @@ struct pinctrl_dev {
* @dev: the device using this pin control handle
* @states: a list of states for this device
* @state: the current state
* @dt_maps: the mapping table chunks dynamically parsed from device tree for
* this device, if any
*/
struct pinctrl {
struct list_head node;
struct device *dev;
struct list_head states;
struct pinctrl_state *state;
struct list_head dt_maps;
};

/**
Expand Down Expand Up @@ -100,7 +103,8 @@ struct pinctrl_setting_configs {
* struct pinctrl_setting - an individual mux or config setting
* @node: list node for struct pinctrl_settings's @settings field
* @type: the type of setting
* @pctldev: pin control device handling to be programmed
* @pctldev: pin control device handling to be programmed. Not used for
* PIN_MAP_TYPE_DUMMY_STATE.
* @data: Data specific to the setting type
*/
struct pinctrl_setting {
Expand Down Expand Up @@ -153,4 +157,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
}

int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup, bool locked);
void pinctrl_unregister_map(struct pinctrl_map const *map);

extern struct mutex pinctrl_mutex;
extern struct list_head pinctrldev_list;
Loading

0 comments on commit 57291ce

Please sign in to comment.