Commit 6e5e959d authored by Stephen Warren's avatar Stephen Warren Committed by Linus Walleij

pinctrl: API changes to support multiple states per device

The API model is changed from:

p = pinctrl_get(dev, "state1");
pinctrl_enable(p);
...
pinctrl_disable(p);
pinctrl_put(p);
p = pinctrl_get(dev, "state2");
pinctrl_enable(p);
...
pinctrl_disable(p);
pinctrl_put(p);

to this:

p = pinctrl_get(dev);
s1 = pinctrl_lookup_state(p, "state1");
s2 = pinctrl_lookup_state(p, "state2");
pinctrl_select_state(p, s1);
...
pinctrl_select_state(p, s2);
...
pinctrl_put(p);

This allows devices to directly transition between states without
disabling the pin controller programming and put()/get()ing the
configuration data each time. This model will also better suit pinconf
programming, which doesn't have a concept of "disable".

The special-case hogging feature of pin controllers is re-written to use
the regular APIs instead of special-case code. Hence, the pinmux-hogs
debugfs file is removed; see the top-level pinctrl-handles files for
equivalent data.
Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarDong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 0e3db173
...@@ -847,8 +847,8 @@ As it is possible to map a function to different groups of pins an optional ...@@ -847,8 +847,8 @@ As it is possible to map a function to different groups of pins an optional
This example mapping is used to switch between two positions for spi0 at This example mapping is used to switch between two positions for spi0 at
runtime, as described further below under the heading "Runtime pinmuxing". runtime, as described further below under the heading "Runtime pinmuxing".
Further it is possible to match several groups of pins to the same function Further it is possible for one named state to affect the muxing of several
for a single device, say for example in the mmc0 example above, where you can groups of pins, say for example in the mmc0 example above, where you can
additively expand the mmc0 bus from 2 to 4 to 8 pins. If we want to use all additively expand the mmc0 bus from 2 to 4 to 8 pins. If we want to use all
three groups for a total of 2+2+4 = 8 pins (for an 8-bit MMC bus as is the three groups for a total of 2+2+4 = 8 pins (for an 8-bit MMC bus as is the
case), we define a mapping like this: case), we define a mapping like this:
...@@ -879,6 +879,7 @@ case), we define a mapping like this: ...@@ -879,6 +879,7 @@ case), we define a mapping like this:
.dev_name = "foo-mmc.0", .dev_name = "foo-mmc.0",
.name = "8bit" .name = "8bit"
.ctrl_dev_name = "pinctrl-foo", .ctrl_dev_name = "pinctrl-foo",
.function = "mmc0",
.group = "mmc0_1_grp", .group = "mmc0_1_grp",
}, },
{ {
...@@ -900,10 +901,16 @@ case), we define a mapping like this: ...@@ -900,10 +901,16 @@ case), we define a mapping like this:
The result of grabbing this mapping from the device with something like The result of grabbing this mapping from the device with something like
this (see next paragraph): this (see next paragraph):
p = pinctrl_get(&device, "8bit"); p = pinctrl_get(dev);
s = pinctrl_lookup_state(p, "8bit");
ret = pinctrl_select_state(p, s);
or more simply:
p = pinctrl_get_select(dev, "8bit");
Will be that you activate all the three bottom records in the mapping at Will be that you activate all the three bottom records in the mapping at
once. Since they share the same name, pin controller device, funcion and once. Since they share the same name, pin controller device, function and
device, and since we allow multiple groups to match to a single device, they device, and since we allow multiple groups to match to a single device, they
all get selected, and they all get enabled and disable simultaneously by the all get selected, and they all get enabled and disable simultaneously by the
pinmux core. pinmux core.
...@@ -925,45 +932,63 @@ default state like this: ...@@ -925,45 +932,63 @@ default state like this:
struct foo_state { struct foo_state {
struct pinctrl *p; struct pinctrl *p;
struct pinctrl_state *s;
... ...
}; };
foo_probe() foo_probe()
{ {
/* Allocate a state holder named "state" etc */ /* Allocate a state holder named "foo" etc */
struct pinctrl p; struct foo_state *foo = ...;
foo->p = pinctrl_get(&device);
if (IS_ERR(foo->p)) {
/* FIXME: clean up "foo" here */
return PTR_ERR(foo->p);
}
p = pinctrl_get(&device, PINCTRL_STATE_DEFAULT); foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
if IS_ERR(p) if (IS_ERR(foo->s)) {
return PTR_ERR(p); pinctrl_put(foo->p);
pinctrl_enable(p); /* FIXME: clean up "foo" here */
return PTR_ERR(s);
}
state->p = p; ret = pinctrl_select_state(foo->s);
if (ret < 0) {
pinctrl_put(foo->p);
/* FIXME: clean up "foo" here */
return ret;
}
} }
foo_remove() foo_remove()
{ {
pinctrl_disable(state->p);
pinctrl_put(state->p); pinctrl_put(state->p);
} }
This get/enable/disable/put sequence can just as well be handled by bus drivers This get/lookup/select/put sequence can just as well be handled by bus drivers
if you don't want each and every driver to handle it and you know the if you don't want each and every driver to handle it and you know the
arrangement on your bus. arrangement on your bus.
The semantics of the get/enable respective disable/put is as follows: The semantics of the pinctrl APIs are:
- pinctrl_get() is called in process context to obtain a handle to all pinctrl
information for a given client device. It will allocate a struct from the
kernel memory to hold the pinmux state. All mapping table parsing or similar
slow operations take place within this API.
- pinctrl_get() is called in process context to reserve the pins affected with - pinctrl_lookup_state() is called in process context to obtain a handle to a
a certain mapping and set up the pinmux core and the driver. It will allocate specific state for a the client device. This operation may be slow too.
a struct from the kernel memory to hold the pinmux state.
- pinctrl_enable()/pinctrl_disable() is quick and can be called from fastpath - pinctrl_select_state() programs pin controller hardware according to the
(irq context) when you quickly want to set up/tear down the hardware muxing definition of the state as given by the mapping table. In theory this is a
when running a device driver. Usually it will just poke some values into a fast-path operation, since it only involved blasting some register settings
register. into hardware. However, note that some pin controllers may have their
registers on a slow/IRQ-based bus, so client devices should not assume they
can call pinctrl_select_state() from non-blocking contexts.
- pinctrl_disable() is called in process context to tear down the pin requests - pinctrl_put() frees all information associated with a pinctrl handle.
and release the state holder struct for the mux setting etc.
Usually the pin control core handled the get/put pair and call out to the Usually the pin control core handled the get/put pair and call out to the
device drivers bookkeeping operations, like checking available functions and device drivers bookkeeping operations, like checking available functions and
...@@ -979,12 +1004,12 @@ System pin control hogging ...@@ -979,12 +1004,12 @@ System pin control hogging
========================== ==========================
Pin control map entries can be hogged by the core when the pin controller Pin control map entries can be hogged by the core when the pin controller
is registered. This means that the core will attempt to call pinctrl_get() and is registered. This means that the core will attempt to call pinctrl_get(),
pinctrl_enable() on it immediately after the pin control device has been lookup_state() and select_state() on it immediately after the pin control
registered. device has been registered.
This is enabled by simply setting the .dev_name field in the map to the name This occurs for mapping table entries where the client device name is equal
of the pin controller itself, like this: to the pin controller device name, and the state name is PINCTRL_STATE_DEFAULT.
{ {
.dev_name = "pinctrl-foo", .dev_name = "pinctrl-foo",
...@@ -1009,8 +1034,8 @@ It is possible to mux a certain function in and out at runtime, say to move ...@@ -1009,8 +1034,8 @@ It is possible to mux a certain function in and out at runtime, say to move
an SPI port from one set of pins to another set of pins. Say for example for an SPI port from one set of pins to another set of pins. Say for example for
spi0 in the example above, we expose two different groups of pins for the same spi0 in the example above, we expose two different groups of pins for the same
function, but with different named in the mapping as described under function, but with different named in the mapping as described under
"Advanced mapping" above. So we have two mappings named "spi0-pos-A" and "Advanced mapping" above. So that for an SPI device, we have two states named
"spi0-pos-B". "pos-A" and "pos-B".
This snippet first muxes the function in the pins defined by group A, enables This snippet first muxes the function in the pins defined by group A, enables
it, disables and releases it, and muxes it in on the pins defined by group B: it, disables and releases it, and muxes it in on the pins defined by group B:
...@@ -1020,23 +1045,36 @@ it, disables and releases it, and muxes it in on the pins defined by group B: ...@@ -1020,23 +1045,36 @@ it, disables and releases it, and muxes it in on the pins defined by group B:
foo_switch() foo_switch()
{ {
struct pinctrl *p; struct pinctrl *p;
struct pinctrl_state *s1, *s2;
/* Setup */
p = pinctrl_get(&device);
if (IS_ERR(p))
...
s1 = pinctrl_lookup_state(foo->p, "pos-A");
if (IS_ERR(s1))
...
s2 = pinctrl_lookup_state(foo->p, "pos-B");
if (IS_ERR(s2))
...
/* Enable on position A */ /* Enable on position A */
p = pinctrl_get(&device, "spi0-pos-A"); ret = pinctrl_select_state(s1);
if IS_ERR(p) if (ret < 0)
return PTR_ERR(p); ...
pinctrl_enable(p);
/* This releases the pins again */ ...
pinctrl_disable(p);
pinctrl_put(p);
/* Enable on position B */ /* Enable on position B */
p = pinctrl_get(&device, "spi0-pos-B"); ret = pinctrl_select_state(s2);
if IS_ERR(p) if (ret < 0)
return PTR_ERR(p); ...
pinctrl_enable(p);
... ...
pinctrl_put(p);
} }
The above has to be done from process context. The above has to be done from process context.
...@@ -1618,22 +1618,18 @@ static struct pinctrl_map __initdata u300_pinmux_map[] = { ...@@ -1618,22 +1618,18 @@ static struct pinctrl_map __initdata u300_pinmux_map[] = {
}; };
struct u300_mux_hog { struct u300_mux_hog {
const char *name;
struct device *dev; struct device *dev;
struct pinctrl *p; struct pinctrl *p;
}; };
static struct u300_mux_hog u300_mux_hogs[] = { static struct u300_mux_hog u300_mux_hogs[] = {
{ {
.name = "uart0",
.dev = &uart0_device.dev, .dev = &uart0_device.dev,
}, },
{ {
.name = "spi0",
.dev = &pl022_device.dev, .dev = &pl022_device.dev,
}, },
{ {
.name = "mmc0",
.dev = &mmcsd_device.dev, .dev = &mmcsd_device.dev,
}, },
}; };
...@@ -1646,16 +1642,10 @@ static int __init u300_pinctrl_fetch(void) ...@@ -1646,16 +1642,10 @@ static int __init u300_pinctrl_fetch(void)
struct pinctrl *p; struct pinctrl *p;
int ret; int ret;
p = pinctrl_get(u300_mux_hogs[i].dev, PINCTRL_STATE_DEFAULT); p = pinctrl_get_select_default(u300_mux_hogs[i].dev);
if (IS_ERR(p)) { if (IS_ERR(p)) {
pr_err("u300: could not get pinmux hog %s\n", pr_err("u300: could not get pinmux hog for dev %s\n",
u300_mux_hogs[i].name); dev_name(u300_mux_hogs[i].dev));
continue;
}
ret = pinctrl_enable(p);
if (ret) {
pr_err("u300: could enable pinmux hog %s\n",
u300_mux_hogs[i].name);
continue; continue;
} }
u300_mux_hogs[i].p = p; u300_mux_hogs[i].p = p;
......
This diff is collapsed.
...@@ -49,22 +49,31 @@ struct pinctrl_dev { ...@@ -49,22 +49,31 @@ struct pinctrl_dev {
* struct pinctrl - per-device pin control state holder * struct pinctrl - per-device pin control state holder
* @node: global list node * @node: global list node
* @dev: the device using this pin control handle * @dev: the device using this pin control handle
* @state: the state name passed to pinctrl_get() * @states: a list of states for this device
* @usecount: the number of active users of this pin controller setting, used * @state: the current state
* to keep track of nested use cases
* @settings: a list of settings for this device/state
*/ */
struct pinctrl { struct pinctrl {
struct list_head node; struct list_head node;
struct device *dev; struct device *dev;
const char *state; struct list_head states;
unsigned usecount; struct pinctrl_state *state;
};
/**
* struct pinctrl_state - a pinctrl state for a device
* @node: list not for struct pinctrl's @states field
* @name: the name of this state
* @settings: a list of settings for this state
*/
struct pinctrl_state {
struct list_head node;
const char *name;
struct list_head settings; struct list_head settings;
}; };
/** /**
* struct pinctrl_setting - an individual mux setting * struct pinctrl_setting - an individual mux setting
* @node: list node for struct pinctrl's @settings field * @node: list node for struct pinctrl_settings's @settings field
* @pctldev: pin control device handling to be programmed * @pctldev: pin control device handling to be programmed
* @group_selector: the group selector to program * @group_selector: the group selector to program
* @func_selector: the function selector to program * @func_selector: the function selector to program
......
...@@ -673,12 +673,10 @@ int sirfsoc_uart_probe(struct platform_device *pdev) ...@@ -673,12 +673,10 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
port->irq = res->start; port->irq = res->start;
if (sirfport->hw_flow_ctrl) { if (sirfport->hw_flow_ctrl) {
sirfport->p = pinctrl_get(&pdev->dev, PINCTRL_STATE_DEFAULT); sirfport->p = pinctrl_get_select_default(&pdev->dev);
ret = IS_ERR(sirfport->p); ret = IS_ERR(sirfport->p);
if (ret) if (ret)
goto pin_err; goto pin_err;
pinctrl_enable(sirfport->p);
} }
port->ops = &sirfsoc_uart_ops; port->ops = &sirfsoc_uart_ops;
...@@ -695,10 +693,8 @@ int sirfsoc_uart_probe(struct platform_device *pdev) ...@@ -695,10 +693,8 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
port_err: port_err:
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl) { if (sirfport->hw_flow_ctrl)
pinctrl_disable(sirfport->p);
pinctrl_put(sirfport->p); pinctrl_put(sirfport->p);
}
pin_err: pin_err:
irq_err: irq_err:
devm_iounmap(&pdev->dev, port->membase); devm_iounmap(&pdev->dev, port->membase);
...@@ -711,10 +707,8 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) ...@@ -711,10 +707,8 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct uart_port *port = &sirfport->port; struct uart_port *port = &sirfport->port;
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl) { if (sirfport->hw_flow_ctrl)
pinctrl_disable(sirfport->p);
pinctrl_put(sirfport->p); pinctrl_put(sirfport->p);
}
devm_iounmap(&pdev->dev, port->membase); devm_iounmap(&pdev->dev, port->membase);
uart_remove_one_port(&sirfsoc_uart_drv, port); uart_remove_one_port(&sirfsoc_uart_drv, port);
return 0; return 0;
......
...@@ -12,12 +12,14 @@ ...@@ -12,12 +12,14 @@
#ifndef __LINUX_PINCTRL_CONSUMER_H #ifndef __LINUX_PINCTRL_CONSUMER_H
#define __LINUX_PINCTRL_CONSUMER_H #define __LINUX_PINCTRL_CONSUMER_H
#include <linux/err.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include "pinctrl.h" #include "pinctrl.h"
/* This struct is private to the core and should be regarded as a cookie */ /* This struct is private to the core and should be regarded as a cookie */
struct pinctrl; struct pinctrl;
struct pinctrl_state;
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
...@@ -26,10 +28,13 @@ extern int pinctrl_request_gpio(unsigned gpio); ...@@ -26,10 +28,13 @@ extern int pinctrl_request_gpio(unsigned gpio);
extern void pinctrl_free_gpio(unsigned gpio); extern void pinctrl_free_gpio(unsigned gpio);
extern int pinctrl_gpio_direction_input(unsigned gpio); extern int pinctrl_gpio_direction_input(unsigned gpio);
extern int pinctrl_gpio_direction_output(unsigned gpio); extern int pinctrl_gpio_direction_output(unsigned gpio);
extern struct pinctrl * __must_check pinctrl_get(struct device *dev, const char *name);
extern struct pinctrl * __must_check pinctrl_get(struct device *dev);
extern void pinctrl_put(struct pinctrl *p); extern void pinctrl_put(struct pinctrl *p);
extern int pinctrl_enable(struct pinctrl *p); extern struct pinctrl_state * __must_check pinctrl_lookup_state(
extern void pinctrl_disable(struct pinctrl *p); struct pinctrl *p,
const char *name);
extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
#else /* !CONFIG_PINCTRL */ #else /* !CONFIG_PINCTRL */
...@@ -52,7 +57,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio) ...@@ -52,7 +57,7 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
return 0; return 0;
} }
static inline struct pinctrl * __must_check pinctrl_get(struct device *dev, const char *name) static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
{ {
return NULL; return NULL;
} }
...@@ -61,17 +66,53 @@ static inline void pinctrl_put(struct pinctrl *p) ...@@ -61,17 +66,53 @@ static inline void pinctrl_put(struct pinctrl *p)
{ {
} }
static inline int pinctrl_enable(struct pinctrl *p) static inline struct pinctrl_state * __must_check pinctrl_lookup_state(
struct pinctrl *p,
const char *name)
{ {
return 0; return NULL;
} }
static inline void pinctrl_disable(struct pinctrl *p) static inline int pinctrl_select_state(struct pinctrl *p,
struct pinctrl_state *s)
{ {
return 0;
} }
#endif /* CONFIG_PINCTRL */ #endif /* CONFIG_PINCTRL */
static inline struct pinctrl * __must_check pinctrl_get_select(
struct device *dev, const char *name)
{
struct pinctrl *p;
struct pinctrl_state *s;
int ret;
p = pinctrl_get(dev);
if (IS_ERR(p))
return p;
s = pinctrl_lookup_state(p, name);
if (IS_ERR(s)) {
pinctrl_put(p);
return ERR_PTR(PTR_ERR(s));
}
ret = pinctrl_select_state(p, s);
if (ret < 0) {
pinctrl_put(p);
return ERR_PTR(ret);
}
return p;
}
static inline struct pinctrl * __must_check pinctrl_get_select_default(
struct device *dev)
{
return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
}
#ifdef CONFIG_PINCONF #ifdef CONFIG_PINCONF
extern int pin_config_get(const char *dev_name, const char *name, extern int pin_config_get(const char *dev_name, const char *name,
......
...@@ -21,23 +21,22 @@ ...@@ -21,23 +21,22 @@
* same name as the pin controllers own dev_name(), the map entry will be * same name as the pin controllers own dev_name(), the map entry will be
* hogged by the driver itself upon registration * hogged by the driver itself upon registration
* @name: the name of this specific map entry for the particular machine. * @name: the name of this specific map entry for the particular machine.
* This is the second parameter passed to pinmux_get() when you want * This is the parameter passed to pinmux_lookup_state()
* to have several mappings to the same device
* @ctrl_dev_name: the name of the device controlling this specific mapping, * @ctrl_dev_name: the name of the device controlling this specific mapping,
* the name must be the same as in your struct device* * the name must be the same as in your struct device*
* @function: a function in the driver to use for this mapping, the driver
* will lookup the function referenced by this ID on the specified
* pin control device
* @group: sometimes a function can map to different pin groups, so this * @group: sometimes a function can map to different pin groups, so this
* selects a certain specific pin group to activate for the function, if * selects a certain specific pin group to activate for the function, if
* left as NULL, the first applicable group will be used * left as NULL, the first applicable group will be used
* @function: a function in the driver to use for this mapping, the driver
* will lookup the function referenced by this ID on the specified
* pin control device
*/ */
struct pinctrl_map { struct pinctrl_map {
const char *dev_name; const char *dev_name;
const char *name; const char *name;
const char *ctrl_dev_name; const char *ctrl_dev_name;
const char *function;
const char *group; const char *group;
const char *function;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment