Messages in this thread | | | Date | Mon, 12 Dec 2011 14:19:22 +0800 | Subject | Re: [PATCH v6] pinctrl: add a pin config interface | From | Haojian Zhuang <> |
| |
On Fri, Dec 9, 2011 at 7:57 PM, Linus Walleij <linus.walleij@stericsson.com> wrote: > From: Linus Walleij <linus.walleij@linaro.org> > > This add per-pin and per-group pin config interfaces for biasing, > driving and other such electronic properties. The details of passed > configurations are passed in an opaque unsigned long which may be > dereferences to integer types, structs or lists on either side > of the configuration interface. > > ChangeLog v1->v2: > - Clear split of terminology: we now have pin controllers, and > those may support two interfaces using vtables: pin > multiplexing and pin configuration. > - Break out pin configuration to its own C file, controllers may > implement only config without mux, and vice versa, so keep each > sub-functionality of pin controllers separate. Introduce > CONFIG_PINCONF in Kconfig. > - Implement some core logic around pin configuration in the > pinconf.c file. > - Remove UNKNOWN config states, these were just surplus baggage. > - Remove FLOAT config state - HIGH_IMPEDANCE should be enough for > everyone. > - PIN_CONFIG_POWER_SOURCE added to handle switching the power > supply for the pin logic between different sources > - Explicit DISABLE config enums to turn schmitt-trigger, > wakeup etc OFF. > - Update documentation to reflect all the recent reasoning. > ChangeLog v2->v3: > - Twist API around to pass around arrays of config tuples instead > of (param, value) pairs everywhere. > - Explicit drive strength semantics for push/pull and similar > drive modes, this shall be the number of drive stages vs > nominal load impedance, which should match the actual > electronics used in push/pull CMOS or TTY totempoles. > - Drop load capacitance configuration - I probably don't know > what I'm doing here so leave it out. > - Drop PIN_CONFIG_INPUT_SCHMITT_OFF, instead the argument zero to > PIN_CONFIG_INPUT_SCHMITT turns schmitt trigger off. > - Drop PIN_CONFIG_NORMAL_POWER_MODE and have a well defined > argument to PIN_CONFIG_LOW_POWER_MODE to get out of it instead. > - Drop PIN_CONFIG_WAKEUP_ENABLE/DISABLE and just use > PIN_CONFIG_WAKEUP with defined value zero to turn wakeup off. > - Add PIN_CONFIG_INPUT_DEBOUNCE for configuring debounce time > on input lines. > - Fix a bug when we tried to configure pins for pin controllers > without pinconf support. > - Initialized debugfs properly so it works. > - Initialize the mutex properly and lock around config tampering > sections. > - Check the return value from get_initial_config() properly. > ChangeLog v3->v4: > - Export the pin_config_get(), pin_config_set() and > pin_config_group() functions. > - Drop the entire concept of just getting initial config and > keeping track of pin states internally, instead ask the pins > what state they are in. Previous idea was plain wrong, if the > device cannot keep track of its state, the driver should do > it. > - Drop the generic configuration layout, it seems this impose > too much restriction on some pin controllers, so let them do > things the way they want and split off support for generic > config as an optional add-on. > ChangeLog v4->v5: > - Introduce two symmetric driver calls for group configuration, > .pin_config_group_[get|set] and corresponding external calls. > - Remove generic semantic meanings of return values from config > calls, these belong in the generic config patch. Just pass the > return value through instead. > - Add a debugfs entry "pinconf-groups" to read status from group > configuration only, also slam in a per-group debug callback in > the pinconf_ops so custom drivers can display something > meaningful for their pins. > - Fix some dangling newline. > - Drop dangling #else clause. > - Update documentation to match the above. > ChangeLog v5->v6: > - Change to using a pin name as parameter for the > [get|set]_config() functions, as suggested by Stephen Warren. > This is more natural as names will be what a developer has > access to in written documentation etc. > > Acked-by: Stephen Warren <swarren@nvidia.com> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > Documentation/pinctrl.txt | 96 ++++++++++++- > drivers/pinctrl/Kconfig | 5 +- > drivers/pinctrl/Makefile | 1 + > drivers/pinctrl/core.c | 37 +++++ > drivers/pinctrl/core.h | 5 + > drivers/pinctrl/pinconf.c | 288 +++++++++++++++++++++++++++++++++++++++ > drivers/pinctrl/pinconf.h | 32 +++++ > include/linux/pinctrl/pinconf.h | 96 +++++++++++++ > include/linux/pinctrl/pinctrl.h | 10 +- > 9 files changed, 559 insertions(+), 11 deletions(-) > create mode 100644 drivers/pinctrl/pinconf.c > create mode 100644 drivers/pinctrl/pinconf.h > create mode 100644 include/linux/pinctrl/pinconf.h > > diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt > index c8fd136..6d23fa8 100644 > --- a/Documentation/pinctrl.txt > +++ b/Documentation/pinctrl.txt > @@ -7,12 +7,9 @@ This subsystem deals with: > > - Multiplexing of pins, pads, fingers (etc) see below for details > > -The intention is to also deal with: > - > -- Software-controlled biasing and driving mode specific pins, such as > - pull-up/down, open drain etc, load capacitance configuration when controlled > - by software, etc. > - > +- Configuration of pins, pads, fingers (etc), such as software-controlled > + biasing and driving mode specific pins, such as pull-up/down, open drain, > + load capacitance etc. > > Top-level interface > =================== > @@ -88,6 +85,11 @@ int __init foo_probe(void) > pr_err("could not register foo pin driver\n"); > } > > +To enable the pinctrl subsystem and the subgroups for PINMUX and PINCONF and > +selected drivers, you need to select them from your machine's Kconfig entry, > +since these are so tightly integrated with the machines they are used on. > +See for example arch/arm/mach-u300/Kconfig for an example. > + > Pins usually have fancier names than this. You can find these in the dataheet > for your chip. Notice that the core pinctrl.h file provides a fancy macro > called PINCTRL_PIN() to create the struct entries. As you can see I enumerated > @@ -193,6 +195,88 @@ structure, for example specific register ranges associated with each group > and so on. > > > +Pin configuration > +================= > + > +Pins can sometimes be software-configured in an various ways, mostly related > +to their electronic properties when used as inputs or outputs. For example you > +may be able to make an output pin high impedance, or "tristate" meaning it is > +effectively disconnected. You may be able to connect an input pin to VDD or GND > +using a certain resistor value - pull up and pull down - so that the pin has a > +stable value when nothing is driving the rail it is connected to, or when it's > +unconnected. > + > +For example, a platform may do this: > + > +ret = pin_config_set(dev, "FOO_GPIO_PIN", PLATFORM_X_PULL_UP); > + > +To pull up a pin to VDD. The pin configuration driver implements callbacks for > +changing pin configuration in the pin controller ops like this: > + > +#include <linux/pinctrl/pinctrl.h> > +#include <linux/pinctrl/pinconf.h> > +#include "platform_x_pindefs.h" > + > +int foo_pin_config_get(struct pinctrl_dev *pctldev, > + unsigned offset, > + unsigned long *config) > +{ > + struct my_conftype conf; > + > + ... Find setting for pin @ offset ... > + > + *config = (unsigned long) conf; > +} > + > +int foo_pin_config_set(struct pinctrl_dev *pctldev, > + unsigned offset, > + unsigned long config) > +{ > + struct my_conftype *conf = (struct my_conftype *) config; > + > + switch (conf) { > + case PLATFORM_X_PULL_UP: > + ... > + } > + } > +} > + > +int foo_pin_config_group_get (struct pinctrl_dev *pctldev, > + unsigned selector, > + unsigned long *config) > +{ > + ... > +} > + > +int foo_pin_config_group_set (struct pinctrl_dev *pctldev, > + unsigned selector, > + unsigned long config) > +{ > + ... > +} > + > +static struct pinconf_ops foo_pconf_ops = { > + .pin_config_get = foo_pin_config_get, > + .pin_config_set = foo_pin_config_set, > + .pin_config_group_get = foo_pin_config_group_get, > + .pin_config_group_set = foo_pin_config_group_set, > +}; > + > +/* Pin config operations are handled by some pin controller */ > +static struct pinctrl_desc foo_desc = { > + ... > + .confops = &foo_pconf_ops, > +}; > + > +Since some controllers have special logic for handling entire groups of pins > +they can exploit the special whole-group pin control function. The > +pin_config_group_set() callback is allowed to return the error code -EAGAIN, > +for groups it does not want to handle, or if it just wants to do some > +group-level handling and then fall through to iterate over all pins, in which > +case each individual pin will be treated by separate pin_config_set() calls as > +well. > + > + > Interaction with the GPIO subsystem > =================================== > > +/** > + * struct pinconf_ops - pin config operations, to be implemented by > + * pin configuration capable drivers. > + * @pin_config_get: get the config of a certain pin, if the requested config > + * is not available on this controller this should return -ENOTSUPP > + * and if it is available but disabled it should return -EINVAL > + * @pin_config_get: get the config of a certain pin > + * @pin_config_set: configure an individual pin > + * @pin_config_group_get: get configurations for an entire pin group > + * @pin_config_group_set: configure all pins in a group > + * @pin_config_dbg_show: optional debugfs display hook that will provide > + * per-device info for a certain pin in debugfs > + * @pin_config_group_dbg_show: optional debugfs display hook that will provide > + * per-device info for a certain group in debugfs > + */ > +struct pinconf_ops { > + int (*pin_config_get) (struct pinctrl_dev *pctldev, > + unsigned pin, > + unsigned long *config); > + int (*pin_config_set) (struct pinctrl_dev *pctldev, > + unsigned pin, > + unsigned long config); > + int (*pin_config_group_get) (struct pinctrl_dev *pctldev, > + unsigned selector, > + unsigned long *config); > + int (*pin_config_group_set) (struct pinctrl_dev *pctldev, > + unsigned selector, > + unsigned long config); > + void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev, > + struct seq_file *s, > + unsigned offset); > + void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev, > + struct seq_file *s, > + unsigned selector); > +}; > + > +extern int pin_config_get(struct pinctrl_dev *pctldev, const char *name, > + unsigned long *config); > +extern int pin_config_set(struct pinctrl_dev *pctldev, const char *name, > + unsigned long config); > +extern int pin_config_group_get(struct pinctrl_dev *pctldev, > + const char *pin_group, > + unsigned long *config); > +extern int pin_config_group_set(struct pinctrl_dev *pctldev, > + const char *pin_group, > + unsigned long config); > + > +#else > + > +static inline int pin_config_get(struct pinctrl_dev *pctldev, const char *name, > + unsigned long *config) > +{ > + return 0; > +} > + > +static inline int pin_config_set(struct pinctrl_dev *pctldev, const char *name, > + unsigned long config) > +{ > + return 0; > +} > + > +static inline int pin_config_group_get(struct pinctrl_dev *pctldev, > + const char *pin_group, > + unsigned long *config) > +{ > + return 0; > +} > + > +static inline int pin_config_group_set(struct pinctrl_dev *pctldev, > + const char *pin_group, > + unsigned long config) > +{ > + return 0; > +} > + > +#endif > +
You mentioned that pin_config_set() is used in below. ret = pin_config_set(dev, "FOO_GPIO_PIN", PLATFORM_X_PULL_UP);
struct pinctrl_dev is created while pinmux is registered. I think this structure is always internal structure. It can't be observed by platform driver or device driver.
I think that you need to add one interface to let platform driver to device driver query the pinctrl_dev. get_pinctrl_dev_from_dev(struct device *dev, const char *dev_name) could take this job, but it is defined in $LINUX/drivers/pinctrl internally too.
Best Regards Haojian -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |