mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge tag 'pinctrl-mergebase-20120418' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl into next/pinctrl
By Stephen Warren (12) and others via Linus Walleij * tag 'pinctrl-mergebase-20120418' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (24 commits) pinctrl: show pin name for pingroups in sysfs pinctrl: show pin name when request pins pinctrl: implement devm_pinctrl_get()/put() pinctrl: a minor fix of pin config debug information pinctrl: pinconf: fix compilation error if PINCONF is not selected pinctrl: allow pctldevs to decode pin config in debugfs pinctrl: ifdef CONFIG_DEBUG_FS cleanup pinctrl: mark non-EXPERIMENTAL pinctrl: tegra: Add complete device tree support dt: Document Tegra20/30 pinctrl binding dt: Move Tegra20 pin mux binding into new pinctrl directory dt: pinctrl: Document device tree binding dt: add property iteration helpers pinctrl: implement pinctrl deferred probing pinctrl: add some error checking for user interfaces pinctrl: fix pinmux_check_ops error checking pinctrl: replace list_*() with get_*_count() pinctrl: mark const init data with __initconst instead of __initdata Documentation: pinctrl: add missing spi0_0 grp in example pinctrl: fix build when CONFIG_OF && !CONFIG_PINCTRL ... Resolved conflicts in drivers/pinctrl/core.c due to same patch being applied in two branches. Signed-off-by: Olof Johansson <[email protected]>
This commit is contained in:
commit
b664ae6ff9
27 changed files with 1350 additions and 188 deletions
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
config PINCTRL
|
||||
bool
|
||||
depends on EXPERIMENTAL
|
||||
|
||||
if PINCTRL
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
|
|||
obj-$(CONFIG_PINCTRL) += core.o
|
||||
obj-$(CONFIG_PINMUX) += pinmux.o
|
||||
obj-$(CONFIG_PINCONF) += pinconf.o
|
||||
ifeq ($(CONFIG_OF),y)
|
||||
obj-$(CONFIG_PINCTRL) += devicetree.o
|
||||
endif
|
||||
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
|
||||
obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
|
||||
obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@
|
|||
#include <linux/sysfs.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include "core.h"
|
||||
#include "devicetree.h"
|
||||
#include "pinmux.h"
|
||||
#include "pinconf.h"
|
||||
|
||||
|
|
@ -45,7 +47,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);
|
||||
|
|
@ -123,6 +125,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pin_get_name_from_id() - look up a pin name from a pin id
|
||||
* @pctldev: the pin control device to lookup the pin on
|
||||
* @name: the name of the pin to look up
|
||||
*/
|
||||
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
|
||||
{
|
||||
const struct pin_desc *desc;
|
||||
|
||||
desc = pin_desc_get(pctldev, pin);
|
||||
if (desc == NULL) {
|
||||
dev_err(pctldev->dev, "failed to get pin(%d) name\n",
|
||||
pin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return desc->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* pin_is_valid() - check if pin exists on controller
|
||||
* @pctldev: the pin control device to check the pin on
|
||||
|
|
@ -318,9 +339,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
|
|||
const char *pin_group)
|
||||
{
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
unsigned ngroups = pctlops->get_groups_count(pctldev);
|
||||
unsigned group_selector = 0;
|
||||
|
||||
while (pctlops->list_groups(pctldev, group_selector) >= 0) {
|
||||
while (group_selector < ngroups) {
|
||||
const char *gname = pctlops->get_group_name(pctldev,
|
||||
group_selector);
|
||||
if (!strcmp(gname, pin_group)) {
|
||||
|
|
@ -516,11 +538,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
|
|||
|
||||
setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
|
||||
if (setting->pctldev == NULL) {
|
||||
dev_err(p->dev, "unknown pinctrl device %s in map entry",
|
||||
dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
|
||||
map->ctrl_dev_name);
|
||||
kfree(setting);
|
||||
/* Eventually, this should trigger deferred probe */
|
||||
return -ENODEV;
|
||||
/*
|
||||
* OK let us guess that the driver is not there yet, and
|
||||
* let's defer obtaining this pinctrl handle to later...
|
||||
*/
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
switch (map->type) {
|
||||
|
|
@ -579,6 +604,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);
|
||||
|
||||
|
|
@ -662,6 +694,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);
|
||||
|
|
@ -787,15 +821,63 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pinctrl_select_state);
|
||||
|
||||
static void devm_pinctrl_release(struct device *dev, void *res)
|
||||
{
|
||||
pinctrl_put(*(struct pinctrl **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* struct devm_pinctrl_get() - Resource managed pinctrl_get()
|
||||
* @dev: the device to obtain the handle for
|
||||
*
|
||||
* If there is a need to explicitly destroy the returned struct pinctrl,
|
||||
* devm_pinctrl_put() should be used, rather than plain pinctrl_put().
|
||||
*/
|
||||
int pinctrl_register_mappings(struct pinctrl_map const *maps,
|
||||
unsigned num_maps)
|
||||
struct pinctrl *devm_pinctrl_get(struct device *dev)
|
||||
{
|
||||
struct pinctrl **ptr, *p;
|
||||
|
||||
ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p = pinctrl_get(dev);
|
||||
if (!IS_ERR(p)) {
|
||||
*ptr = p;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pinctrl_get);
|
||||
|
||||
static int devm_pinctrl_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct pinctrl **p = res;
|
||||
|
||||
return *p == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_pinctrl_put() - Resource managed pinctrl_put()
|
||||
* @p: the pinctrl handle to release
|
||||
*
|
||||
* Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
|
||||
* this function will not need to be called and the resource management
|
||||
* code will ensure that the resource is freed.
|
||||
*/
|
||||
void devm_pinctrl_put(struct pinctrl *p)
|
||||
{
|
||||
WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
|
||||
devm_pinctrl_match, p));
|
||||
pinctrl_put(p);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pinctrl_put);
|
||||
|
||||
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
|
||||
bool dup, bool locked)
|
||||
{
|
||||
int i, ret;
|
||||
struct pinctrl_maps *maps_node;
|
||||
|
|
@ -851,20 +933,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)
|
||||
|
|
@ -906,15 +1020,17 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
|
|||
{
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
unsigned selector = 0;
|
||||
unsigned ngroups, selector = 0;
|
||||
|
||||
ngroups = ops->get_groups_count(pctldev);
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
|
||||
seq_puts(s, "registered pin groups:\n");
|
||||
while (ops->list_groups(pctldev, selector) >= 0) {
|
||||
while (selector < ngroups) {
|
||||
const unsigned *pins;
|
||||
unsigned num_pins;
|
||||
const char *gname = ops->get_group_name(pctldev, selector);
|
||||
const char *pname;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
|
|
@ -924,10 +1040,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
|
|||
seq_printf(s, "%s [ERROR GETTING PINS]\n",
|
||||
gname);
|
||||
else {
|
||||
seq_printf(s, "group: %s, pins = [ ", gname);
|
||||
for (i = 0; i < num_pins; i++)
|
||||
seq_printf(s, "%d ", pins[i]);
|
||||
seq_puts(s, "]\n");
|
||||
seq_printf(s, "group: %s\n", gname);
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
pname = pin_get_name(pctldev, pins[i]);
|
||||
if (WARN_ON(!pname))
|
||||
return -EINVAL;
|
||||
seq_printf(s, "pin %d (%s)\n", pins[i], pname);
|
||||
}
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
selector++;
|
||||
}
|
||||
|
|
@ -1226,11 +1346,14 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
|
|||
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
|
||||
if (!ops ||
|
||||
!ops->list_groups ||
|
||||
!ops->get_groups_count ||
|
||||
!ops->get_group_name ||
|
||||
!ops->get_group_pins)
|
||||
return -EINVAL;
|
||||
|
||||
if (ops->dt_node_to_map && !ops->dt_free_map)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -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 {
|
||||
|
|
@ -144,6 +148,7 @@ struct pin_desc {
|
|||
|
||||
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
|
||||
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
|
||||
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
|
||||
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
|
||||
const char *pin_group);
|
||||
|
||||
|
|
@ -153,4 +158,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;
|
||||
|
|
|
|||
249
drivers/pinctrl/devicetree.c
Normal file
249
drivers/pinctrl/devicetree.c
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Device tree integration for the pin control subsystem
|
||||
*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "devicetree.h"
|
||||
|
||||
/**
|
||||
* struct pinctrl_dt_map - mapping table chunk parsed from device tree
|
||||
* @node: list node for struct pinctrl's @dt_maps field
|
||||
* @pctldev: the pin controller that allocated this struct, and will free it
|
||||
* @maps: the mapping table entries
|
||||
*/
|
||||
struct pinctrl_dt_map {
|
||||
struct list_head node;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_map *map;
|
||||
unsigned num_maps;
|
||||
};
|
||||
|
||||
static void dt_free_map(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
if (pctldev) {
|
||||
struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
ops->dt_free_map(pctldev, map, num_maps);
|
||||
} else {
|
||||
/* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
|
||||
kfree(map);
|
||||
}
|
||||
}
|
||||
|
||||
void pinctrl_dt_free_maps(struct pinctrl *p)
|
||||
{
|
||||
struct pinctrl_dt_map *dt_map, *n1;
|
||||
|
||||
list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) {
|
||||
pinctrl_unregister_map(dt_map->map);
|
||||
list_del(&dt_map->node);
|
||||
dt_free_map(dt_map->pctldev, dt_map->map,
|
||||
dt_map->num_maps);
|
||||
kfree(dt_map);
|
||||
}
|
||||
|
||||
of_node_put(p->dev->of_node);
|
||||
}
|
||||
|
||||
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
|
||||
struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
int i;
|
||||
struct pinctrl_dt_map *dt_map;
|
||||
|
||||
/* Initialize common mapping table entry fields */
|
||||
for (i = 0; i < num_maps; i++) {
|
||||
map[i].dev_name = dev_name(p->dev);
|
||||
map[i].name = statename;
|
||||
if (pctldev)
|
||||
map[i].ctrl_dev_name = dev_name(pctldev->dev);
|
||||
}
|
||||
|
||||
/* Remember the converted mapping table entries */
|
||||
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
|
||||
if (!dt_map) {
|
||||
dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
|
||||
dt_free_map(pctldev, map, num_maps);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dt_map->pctldev = pctldev;
|
||||
dt_map->map = map;
|
||||
dt_map->num_maps = num_maps;
|
||||
list_add_tail(&dt_map->node, &p->dt_maps);
|
||||
|
||||
return pinctrl_register_map(map, num_maps, false, true);
|
||||
}
|
||||
|
||||
static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
|
||||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
|
||||
list_for_each_entry(pctldev, &pinctrldev_list, node)
|
||||
if (pctldev->dev->of_node == np)
|
||||
return pctldev;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
|
||||
struct device_node *np_config)
|
||||
{
|
||||
struct device_node *np_pctldev;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_ops *ops;
|
||||
int ret;
|
||||
struct pinctrl_map *map;
|
||||
unsigned num_maps;
|
||||
|
||||
/* Find the pin controller containing np_config */
|
||||
np_pctldev = of_node_get(np_config);
|
||||
for (;;) {
|
||||
np_pctldev = of_get_next_parent(np_pctldev);
|
||||
if (!np_pctldev || of_node_is_root(np_pctldev)) {
|
||||
dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
|
||||
np_config->full_name);
|
||||
of_node_put(np_pctldev);
|
||||
/* OK let's just assume this will appear later then */
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
pctldev = find_pinctrl_by_of_node(np_pctldev);
|
||||
if (pctldev)
|
||||
break;
|
||||
}
|
||||
of_node_put(np_pctldev);
|
||||
|
||||
/*
|
||||
* Call pinctrl driver to parse device tree node, and
|
||||
* generate mapping table entries
|
||||
*/
|
||||
ops = pctldev->desc->pctlops;
|
||||
if (!ops->dt_node_to_map) {
|
||||
dev_err(p->dev, "pctldev %s doesn't support DT\n",
|
||||
dev_name(pctldev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Stash the mapping table chunk away for later use */
|
||||
return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
|
||||
}
|
||||
|
||||
static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
|
||||
{
|
||||
struct pinctrl_map *map;
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map) {
|
||||
dev_err(p->dev, "failed to alloc struct pinctrl_map\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
|
||||
map->type = PIN_MAP_TYPE_DUMMY_STATE;
|
||||
|
||||
return dt_remember_or_free_map(p, statename, NULL, map, 1);
|
||||
}
|
||||
|
||||
int pinctrl_dt_to_map(struct pinctrl *p)
|
||||
{
|
||||
struct device_node *np = p->dev->of_node;
|
||||
int state, ret;
|
||||
char *propname;
|
||||
struct property *prop;
|
||||
const char *statename;
|
||||
const __be32 *list;
|
||||
int size, config;
|
||||
phandle phandle;
|
||||
struct device_node *np_config;
|
||||
|
||||
/* CONFIG_OF enabled, p->dev not instantiated from DT */
|
||||
if (!np) {
|
||||
dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We may store pointers to property names within the node */
|
||||
of_node_get(np);
|
||||
|
||||
/* For each defined state ID */
|
||||
for (state = 0; ; state++) {
|
||||
/* Retrieve the pinctrl-* property */
|
||||
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
|
||||
prop = of_find_property(np, propname, &size);
|
||||
kfree(propname);
|
||||
if (!prop)
|
||||
break;
|
||||
list = prop->value;
|
||||
size /= sizeof(*list);
|
||||
|
||||
/* Determine whether pinctrl-names property names the state */
|
||||
ret = of_property_read_string_index(np, "pinctrl-names",
|
||||
state, &statename);
|
||||
/*
|
||||
* If not, statename is just the integer state ID. But rather
|
||||
* than dynamically allocate it and have to free it later,
|
||||
* just point part way into the property name for the string.
|
||||
*/
|
||||
if (ret < 0) {
|
||||
/* strlen("pinctrl-") == 8 */
|
||||
statename = prop->name + 8;
|
||||
}
|
||||
|
||||
/* For every referenced pin configuration node in it */
|
||||
for (config = 0; config < size; config++) {
|
||||
phandle = be32_to_cpup(list++);
|
||||
|
||||
/* Look up the pin configuration node */
|
||||
np_config = of_find_node_by_phandle(phandle);
|
||||
if (!np_config) {
|
||||
dev_err(p->dev,
|
||||
"prop %s index %i invalid phandle\n",
|
||||
prop->name, config);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Parse the node */
|
||||
ret = dt_to_map_one_config(p, statename, np_config);
|
||||
of_node_put(np_config);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* No entries in DT? Generate a dummy state table entry */
|
||||
if (!size) {
|
||||
ret = dt_remember_dummy_state(p, statename);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pinctrl_dt_free_maps(p);
|
||||
return ret;
|
||||
}
|
||||
35
drivers/pinctrl/devicetree.h
Normal file
35
drivers/pinctrl/devicetree.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Internal interface to pinctrl device tree integration
|
||||
*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
void pinctrl_dt_free_maps(struct pinctrl *p);
|
||||
int pinctrl_dt_to_map(struct pinctrl *p);
|
||||
|
||||
#else
|
||||
|
||||
static inline int pinctrl_dt_to_map(struct pinctrl *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void pinctrl_dt_free_maps(struct pinctrl *p)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -379,8 +379,16 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
|
|||
|
||||
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
|
||||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
const struct pinconf_ops *confops;
|
||||
int i;
|
||||
|
||||
pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
|
||||
if (pctldev)
|
||||
confops = pctldev->desc->confops;
|
||||
else
|
||||
confops = NULL;
|
||||
|
||||
switch (map->type) {
|
||||
case PIN_MAP_TYPE_CONFIGS_PIN:
|
||||
seq_printf(s, "pin ");
|
||||
|
|
@ -394,8 +402,15 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
|
|||
|
||||
seq_printf(s, "%s\n", map->data.configs.group_or_pin);
|
||||
|
||||
for (i = 0; i < map->data.configs.num_configs; i++)
|
||||
seq_printf(s, "config %08lx\n", map->data.configs.configs[i]);
|
||||
for (i = 0; i < map->data.configs.num_configs; i++) {
|
||||
seq_printf(s, "config ");
|
||||
if (confops && confops->pin_config_config_dbg_show)
|
||||
confops->pin_config_config_dbg_show(pctldev, s,
|
||||
map->data.configs.configs[i]);
|
||||
else
|
||||
seq_printf(s, "%08lx", map->data.configs.configs[i]);
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void pinconf_show_setting(struct seq_file *s,
|
||||
|
|
@ -403,6 +418,7 @@ void pinconf_show_setting(struct seq_file *s,
|
|||
{
|
||||
struct pinctrl_dev *pctldev = setting->pctldev;
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
const struct pinconf_ops *confops = pctldev->desc->confops;
|
||||
struct pin_desc *desc;
|
||||
int i;
|
||||
|
||||
|
|
@ -428,8 +444,15 @@ void pinconf_show_setting(struct seq_file *s,
|
|||
* FIXME: We should really get the pin controler to dump the config
|
||||
* values, so they can be decoded to something meaningful.
|
||||
*/
|
||||
for (i = 0; i < setting->data.configs.num_configs; i++)
|
||||
seq_printf(s, " %08lx", setting->data.configs.configs[i]);
|
||||
for (i = 0; i < setting->data.configs.num_configs; i++) {
|
||||
seq_printf(s, " ");
|
||||
if (confops && confops->pin_config_config_dbg_show)
|
||||
confops->pin_config_config_dbg_show(pctldev, s,
|
||||
setting->data.configs.configs[i]);
|
||||
else
|
||||
seq_printf(s, "%08lx",
|
||||
setting->data.configs.configs[i]);
|
||||
}
|
||||
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
|
|
@ -448,10 +471,14 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
|
|||
static int pinconf_pins_show(struct seq_file *s, void *what)
|
||||
{
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinconf_ops *ops = pctldev->desc->confops;
|
||||
unsigned i, pin;
|
||||
|
||||
if (!ops || !ops->pin_config_get)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Pin config settings per pin\n");
|
||||
seq_puts(s, "Format: pin (name): pinmux setting array\n");
|
||||
seq_puts(s, "Format: pin (name): configs\n");
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
|
||||
|
|
@ -495,17 +522,18 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
|
|||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
const struct pinconf_ops *ops = pctldev->desc->confops;
|
||||
unsigned ngroups = pctlops->get_groups_count(pctldev);
|
||||
unsigned selector = 0;
|
||||
|
||||
if (!ops || !ops->pin_config_group_get)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Pin config settings per pin group\n");
|
||||
seq_puts(s, "Format: group (name): pinmux setting array\n");
|
||||
seq_puts(s, "Format: group (name): configs\n");
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
|
||||
while (pctlops->list_groups(pctldev, selector) >= 0) {
|
||||
while (selector < ngroups) {
|
||||
const char *gname = pctlops->get_group_name(pctldev, selector);
|
||||
|
||||
seq_printf(s, "%u (%s):", selector, gname);
|
||||
|
|
|
|||
|
|
@ -19,11 +19,6 @@ int pinconf_map_to_setting(struct pinctrl_map const *map,
|
|||
struct pinctrl_setting *setting);
|
||||
void pinconf_free_setting(struct pinctrl_setting const *setting);
|
||||
int pinconf_apply_setting(struct pinctrl_setting const *setting);
|
||||
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinconf_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinconf_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
/*
|
||||
* You will only be interested in these if you're using PINCONF
|
||||
|
|
@ -61,6 +56,18 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)
|
||||
|
||||
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinconf_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinconf_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void pinconf_show_map(struct seq_file *s,
|
||||
struct pinctrl_map const *map)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ struct u300_gpio_confdata {
|
|||
|
||||
|
||||
/* Initial configuration */
|
||||
static const struct __initdata u300_gpio_confdata
|
||||
static const struct __initconst u300_gpio_confdata
|
||||
bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
||||
/* Port 0, pins 0-7 */
|
||||
{
|
||||
|
|
@ -255,7 +255,7 @@ bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
|||
}
|
||||
};
|
||||
|
||||
static const struct __initdata u300_gpio_confdata
|
||||
static const struct __initconst u300_gpio_confdata
|
||||
bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
||||
/* Port 0, pins 0-7 */
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
|
|||
.pin_base = 0,
|
||||
};
|
||||
|
||||
static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
|
||||
static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (selector >= info->num_grps)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
return info->num_grps;
|
||||
}
|
||||
|
||||
static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (selector >= info->num_grps)
|
||||
return NULL;
|
||||
|
||||
return info->grps[selector].name;
|
||||
}
|
||||
|
||||
|
|
@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
|
|||
unsigned *num_pins)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (selector >= info->num_grps)
|
||||
return -EINVAL;
|
||||
|
||||
*pins = info->grps[selector].pins;
|
||||
*num_pins = info->grps[selector].npins;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops pxa3xx_pctrl_ops = {
|
||||
.list_groups = pxa3xx_list_groups,
|
||||
.get_groups_count = pxa3xx_get_groups_count,
|
||||
.get_group_name = pxa3xx_get_group_name,
|
||||
.get_group_pins = pxa3xx_get_group_pins,
|
||||
};
|
||||
|
||||
static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
|
||||
static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (func >= info->num_funcs)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
return info->num_funcs;
|
||||
}
|
||||
|
||||
static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
|
||||
|
|
@ -170,7 +166,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
|
|||
}
|
||||
|
||||
static struct pinmux_ops pxa3xx_pmx_ops = {
|
||||
.list_functions = pxa3xx_pmx_list_func,
|
||||
.get_functions_count = pxa3xx_pmx_get_funcs_count,
|
||||
.get_function_name = pxa3xx_pmx_get_func_name,
|
||||
.get_function_groups = pxa3xx_pmx_get_groups,
|
||||
.enable = pxa3xx_pmx_enable,
|
||||
|
|
|
|||
|
|
@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
|
|||
SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
|
||||
};
|
||||
|
||||
static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(sirfsoc_pin_groups);
|
||||
}
|
||||
|
||||
static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned selector)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
|
||||
return NULL;
|
||||
return sirfsoc_pin_groups[selector].name;
|
||||
}
|
||||
|
||||
|
|
@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector
|
|||
const unsigned **pins,
|
||||
unsigned *num_pins)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
|
||||
return -EINVAL;
|
||||
*pins = sirfsoc_pin_groups[selector].pins;
|
||||
*num_pins = sirfsoc_pin_groups[selector].num_pins;
|
||||
return 0;
|
||||
|
|
@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
|
|||
}
|
||||
|
||||
static struct pinctrl_ops sirfsoc_pctrl_ops = {
|
||||
.list_groups = sirfsoc_list_groups,
|
||||
.get_groups_count = sirfsoc_get_groups_count,
|
||||
.get_group_name = sirfsoc_get_group_name,
|
||||
.get_group_pins = sirfsoc_get_group_pins,
|
||||
.pin_dbg_show = sirfsoc_pin_dbg_show,
|
||||
|
|
@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector
|
|||
sirfsoc_pinmux_endisable(spmx, selector, false);
|
||||
}
|
||||
|
||||
static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
|
||||
static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(sirfsoc_pmx_functions);
|
||||
}
|
||||
|
||||
static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
|
||||
|
|
@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
|
|||
}
|
||||
|
||||
static struct pinmux_ops sirfsoc_pinmux_ops = {
|
||||
.list_functions = sirfsoc_pinmux_list_funcs,
|
||||
.enable = sirfsoc_pinmux_enable,
|
||||
.disable = sirfsoc_pinmux_disable,
|
||||
.get_functions_count = sirfsoc_pinmux_get_funcs_count,
|
||||
.get_function_name = sirfsoc_pinmux_get_func_name,
|
||||
.get_function_groups = sirfsoc_pinmux_get_groups,
|
||||
.gpio_request_enable = sirfsoc_pinmux_request_gpio,
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <mach/pinconf-tegra.h>
|
||||
|
||||
|
|
@ -53,15 +55,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
|
|||
writel(val, pmx->regs[bank] + reg);
|
||||
}
|
||||
|
||||
static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
|
||||
unsigned group)
|
||||
static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return pmx->soc->ngroups;
|
||||
}
|
||||
|
||||
static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
|
|
@ -69,9 +67,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return NULL;
|
||||
|
||||
return pmx->soc->groups[group].name;
|
||||
}
|
||||
|
||||
|
|
@ -82,9 +77,6 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
|
||||
*pins = pmx->soc->groups[group].pins;
|
||||
*num_pins = pmx->soc->groups[group].npins;
|
||||
|
||||
|
|
@ -98,22 +90,221 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
|||
seq_printf(s, " " DRIVER_NAME);
|
||||
}
|
||||
|
||||
static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
|
||||
unsigned *num_maps, unsigned reserve)
|
||||
{
|
||||
unsigned old_num = *reserved_maps;
|
||||
unsigned new_num = *num_maps + reserve;
|
||||
struct pinctrl_map *new_map;
|
||||
|
||||
if (old_num >= new_num)
|
||||
return 0;
|
||||
|
||||
new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
|
||||
if (!new_map)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
|
||||
|
||||
*map = new_map;
|
||||
*reserved_maps = new_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
|
||||
unsigned *num_maps, const char *group,
|
||||
const char *function)
|
||||
{
|
||||
if (*num_maps == *reserved_maps)
|
||||
return -ENOSPC;
|
||||
|
||||
(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
|
||||
(*map)[*num_maps].data.mux.group = group;
|
||||
(*map)[*num_maps].data.mux.function = function;
|
||||
(*num_maps)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps,
|
||||
unsigned *num_maps, const char *group,
|
||||
unsigned long *configs, unsigned num_configs)
|
||||
{
|
||||
unsigned long *dup_configs;
|
||||
|
||||
if (*num_maps == *reserved_maps)
|
||||
return -ENOSPC;
|
||||
|
||||
dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
|
||||
GFP_KERNEL);
|
||||
if (!dup_configs)
|
||||
return -ENOMEM;
|
||||
|
||||
(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
|
||||
(*map)[*num_maps].data.configs.group_or_pin = group;
|
||||
(*map)[*num_maps].data.configs.configs = dup_configs;
|
||||
(*map)[*num_maps].data.configs.num_configs = num_configs;
|
||||
(*num_maps)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_config(unsigned long **configs, unsigned *num_configs,
|
||||
unsigned long config)
|
||||
{
|
||||
unsigned old_num = *num_configs;
|
||||
unsigned new_num = old_num + 1;
|
||||
unsigned long *new_configs;
|
||||
|
||||
new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
|
||||
GFP_KERNEL);
|
||||
if (!new_configs)
|
||||
return -ENOMEM;
|
||||
|
||||
new_configs[old_num] = config;
|
||||
|
||||
*configs = new_configs;
|
||||
*num_configs = new_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_maps; i++)
|
||||
if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
|
||||
kfree(map[i].data.configs.configs);
|
||||
|
||||
kfree(map);
|
||||
}
|
||||
|
||||
static const struct cfg_param {
|
||||
const char *property;
|
||||
enum tegra_pinconf_param param;
|
||||
} cfg_params[] = {
|
||||
{"nvidia,pull", TEGRA_PINCONF_PARAM_PULL},
|
||||
{"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE},
|
||||
{"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT},
|
||||
{"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN},
|
||||
{"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK},
|
||||
{"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET},
|
||||
{"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE},
|
||||
{"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT},
|
||||
{"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE},
|
||||
{"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH},
|
||||
{"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH},
|
||||
{"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
|
||||
{"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
|
||||
};
|
||||
|
||||
int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
|
||||
struct pinctrl_map **map,
|
||||
unsigned *reserved_maps,
|
||||
unsigned *num_maps)
|
||||
{
|
||||
int ret, i;
|
||||
const char *function;
|
||||
u32 val;
|
||||
unsigned long config;
|
||||
unsigned long *configs = NULL;
|
||||
unsigned num_configs = 0;
|
||||
unsigned reserve;
|
||||
struct property *prop;
|
||||
const char *group;
|
||||
|
||||
ret = of_property_read_string(np, "nvidia,function", &function);
|
||||
if (ret < 0)
|
||||
function = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
|
||||
ret = of_property_read_u32(np, cfg_params[i].property, &val);
|
||||
if (!ret) {
|
||||
config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
|
||||
ret = add_config(&configs, &num_configs, config);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
reserve = 0;
|
||||
if (function != NULL)
|
||||
reserve++;
|
||||
if (num_configs)
|
||||
reserve++;
|
||||
ret = of_property_count_strings(np, "nvidia,pins");
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
reserve *= ret;
|
||||
|
||||
ret = reserve_map(map, reserved_maps, num_maps, reserve);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
of_property_for_each_string(np, "nvidia,pins", prop, group) {
|
||||
if (function) {
|
||||
ret = add_map_mux(map, reserved_maps, num_maps,
|
||||
group, function);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (num_configs) {
|
||||
ret = add_map_configs(map, reserved_maps, num_maps,
|
||||
group, configs, num_configs);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
kfree(configs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
struct device_node *np_config,
|
||||
struct pinctrl_map **map, unsigned *num_maps)
|
||||
{
|
||||
unsigned reserved_maps;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
reserved_maps = 0;
|
||||
*map = NULL;
|
||||
*num_maps = 0;
|
||||
|
||||
for_each_child_of_node(np_config, np) {
|
||||
ret = tegra_pinctrl_dt_subnode_to_map(np, map, &reserved_maps,
|
||||
num_maps);
|
||||
if (ret < 0) {
|
||||
tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops tegra_pinctrl_ops = {
|
||||
.list_groups = tegra_pinctrl_list_groups,
|
||||
.get_groups_count = tegra_pinctrl_get_groups_count,
|
||||
.get_group_name = tegra_pinctrl_get_group_name,
|
||||
.get_group_pins = tegra_pinctrl_get_group_pins,
|
||||
.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
|
||||
.dt_node_to_map = tegra_pinctrl_dt_node_to_map,
|
||||
.dt_free_map = tegra_pinctrl_dt_free_map,
|
||||
};
|
||||
|
||||
static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
|
||||
unsigned function)
|
||||
static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return pmx->soc->nfunctions;
|
||||
}
|
||||
|
||||
static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
|
||||
|
|
@ -121,9 +312,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return NULL;
|
||||
|
||||
return pmx->soc->functions[function].name;
|
||||
}
|
||||
|
||||
|
|
@ -134,9 +322,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
|
|||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return -EINVAL;
|
||||
|
||||
*groups = pmx->soc->functions[function].groups;
|
||||
*num_groups = pmx->soc->functions[function].ngroups;
|
||||
|
||||
|
|
@ -151,8 +336,6 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
|
|||
int i;
|
||||
u32 val;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
if (g->mux_reg < 0)
|
||||
|
|
@ -180,8 +363,6 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
|
|||
const struct tegra_pingroup *g;
|
||||
u32 val;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
if (g->mux_reg < 0)
|
||||
|
|
@ -194,7 +375,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
static struct pinmux_ops tegra_pinmux_ops = {
|
||||
.list_functions = tegra_pinctrl_list_funcs,
|
||||
.get_functions_count = tegra_pinctrl_get_funcs_count,
|
||||
.get_function_name = tegra_pinctrl_get_func_name,
|
||||
.get_function_groups = tegra_pinctrl_get_func_groups,
|
||||
.enable = tegra_pinctrl_enable,
|
||||
|
|
@ -324,8 +505,6 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
|
|||
s16 reg;
|
||||
u32 val, mask;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
|
||||
|
|
@ -353,8 +532,6 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
|
|||
s16 reg;
|
||||
u32 val, mask;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
|
||||
|
|
|
|||
|
|
@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int u300_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pin_groups))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(u300_pin_groups);
|
||||
}
|
||||
|
||||
static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned selector)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pin_groups))
|
||||
return NULL;
|
||||
return u300_pin_groups[selector].name;
|
||||
}
|
||||
|
||||
|
|
@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
|
|||
const unsigned **pins,
|
||||
unsigned *num_pins)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pin_groups))
|
||||
return -EINVAL;
|
||||
*pins = u300_pin_groups[selector].pins;
|
||||
*num_pins = u300_pin_groups[selector].num_pins;
|
||||
return 0;
|
||||
|
|
@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
|
|||
}
|
||||
|
||||
static struct pinctrl_ops u300_pctrl_ops = {
|
||||
.list_groups = u300_list_groups,
|
||||
.get_groups_count = u300_get_groups_count,
|
||||
.get_group_name = u300_get_group_name,
|
||||
.get_group_pins = u300_get_group_pins,
|
||||
.pin_dbg_show = u300_pin_dbg_show,
|
||||
|
|
@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
|
|||
u300_pmx_endisable(upmx, selector, false);
|
||||
}
|
||||
|
||||
static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pmx_functions))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(u300_pmx_functions);
|
||||
}
|
||||
|
||||
static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
|
||||
|
|
@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
|
|||
}
|
||||
|
||||
static struct pinmux_ops u300_pmx_ops = {
|
||||
.list_functions = u300_pmx_list_funcs,
|
||||
.get_functions_count = u300_pmx_get_funcs_count,
|
||||
.get_function_name = u300_pmx_get_func_name,
|
||||
.get_function_groups = u300_pmx_get_groups,
|
||||
.enable = u300_pmx_enable,
|
||||
|
|
|
|||
|
|
@ -33,10 +33,12 @@
|
|||
int pinmux_check_ops(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
const struct pinmux_ops *ops = pctldev->desc->pmxops;
|
||||
unsigned nfuncs;
|
||||
unsigned selector = 0;
|
||||
|
||||
/* Check that we implement required operations */
|
||||
if (!ops->list_functions ||
|
||||
if (!ops ||
|
||||
!ops->get_functions_count ||
|
||||
!ops->get_function_name ||
|
||||
!ops->get_function_groups ||
|
||||
!ops->enable ||
|
||||
|
|
@ -44,11 +46,12 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev)
|
|||
return -EINVAL;
|
||||
|
||||
/* Check that all functions registered have names */
|
||||
while (ops->list_functions(pctldev, selector) >= 0) {
|
||||
nfuncs = ops->get_functions_count(pctldev);
|
||||
while (selector < nfuncs) {
|
||||
const char *fname = ops->get_function_name(pctldev,
|
||||
selector);
|
||||
if (!fname) {
|
||||
pr_err("pinmux ops has no name for function%u\n",
|
||||
dev_err(pctldev->dev, "pinmux ops has no name for function%u\n",
|
||||
selector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -85,8 +88,6 @@ static int pin_request(struct pinctrl_dev *pctldev,
|
|||
const struct pinmux_ops *ops = pctldev->desc->pmxops;
|
||||
int status = -EINVAL;
|
||||
|
||||
dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
|
||||
|
||||
desc = pin_desc_get(pctldev, pin);
|
||||
if (desc == NULL) {
|
||||
dev_err(pctldev->dev,
|
||||
|
|
@ -94,6 +95,9 @@ static int pin_request(struct pinctrl_dev *pctldev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
|
||||
pin, desc->name, owner);
|
||||
|
||||
if (gpio_range) {
|
||||
/* There's no need to support multiple GPIO requests */
|
||||
if (desc->gpio_owner) {
|
||||
|
|
@ -287,10 +291,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
|
|||
const char *function)
|
||||
{
|
||||
const struct pinmux_ops *ops = pctldev->desc->pmxops;
|
||||
unsigned nfuncs = ops->get_functions_count(pctldev);
|
||||
unsigned selector = 0;
|
||||
|
||||
/* See if this pctldev has this function */
|
||||
while (ops->list_functions(pctldev, selector) >= 0) {
|
||||
while (selector < nfuncs) {
|
||||
const char *fname = ops->get_function_name(pctldev,
|
||||
selector);
|
||||
|
||||
|
|
@ -319,6 +324,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
|
|||
const unsigned *pins;
|
||||
unsigned num_pins;
|
||||
|
||||
if (!pmxops) {
|
||||
dev_err(pctldev->dev, "does not support mux function\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
setting->data.mux.func =
|
||||
pinmux_func_name_to_selector(pctldev, map->data.mux.function);
|
||||
if (setting->data.mux.func < 0)
|
||||
|
|
@ -477,11 +487,15 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
|
|||
{
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
|
||||
unsigned nfuncs;
|
||||
unsigned func_selector = 0;
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
if (!pmxops)
|
||||
return 0;
|
||||
|
||||
while (pmxops->list_functions(pctldev, func_selector) >= 0) {
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
nfuncs = pmxops->get_functions_count(pctldev);
|
||||
while (func_selector < nfuncs) {
|
||||
const char *func = pmxops->get_function_name(pctldev,
|
||||
func_selector);
|
||||
const char * const *groups;
|
||||
|
|
@ -515,6 +529,9 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
|
|||
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
|
||||
unsigned i, pin;
|
||||
|
||||
if (!pmxops)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Pinmux settings per pin\n");
|
||||
seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -31,12 +31,6 @@ void pinmux_free_setting(struct pinctrl_setting const *setting);
|
|||
int pinmux_enable_setting(struct pinctrl_setting const *setting);
|
||||
void pinmux_disable_setting(struct pinctrl_setting const *setting);
|
||||
|
||||
void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinmux_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinmux_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int pinmux_check_ops(struct pinctrl_dev *pctldev)
|
||||
|
|
@ -89,6 +83,18 @@ static inline void pinmux_disable_setting(
|
|||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS)
|
||||
|
||||
void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinmux_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinmux_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void pinmux_show_map(struct seq_file *s,
|
||||
struct pinctrl_map const *map)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue