[PATCH 1/4 v4] drivers: create a pin control subsystem

Jamie Iles jamie at jamieiles.com
Fri Aug 19 10:26:08 EDT 2011


Hi Linus,

On Fri, Aug 19, 2011 at 04:04:54PM +0200, Linus Walleij wrote:
> On Fri, Aug 19, 2011 at 12:48 PM, Jamie Iles <jamie at jamieiles.com> wrote:
> > On Fri, Aug 19, 2011 at 11:53:50AM +0200, Linus Walleij wrote:
> >> +Interaction with the GPIO subsystem
> >> +===================================
> >> +
> >> +The GPIO drivers may want to perform operations of various types on the same
> >> +physical pins that are also registered as GPIO pins.
> >> +
> >> +Since the pin controller subsystem have its pinspace local to the pin
> >> +controller we need a mapping so that the pin control subsystem can figure out
> >> +which pin controller handles control of a certain GPIO pin. This member
> >> +in the pin controller descriptor handles this mapping:
> >> +
> >> +static struct pinctrl_desc foo_desc = {
> >> +     ...
> >> +     .gpio_base = FIRST_PIN,
> >> +};
> >> +
> >> +When GPIO-specific functions in the pin control subsystem are called, these
> >> +mappings will be used to look up the apropriate pin controller by inspecting
> >> +and matching the pin to this pin range.
> >
> > On our (difficultly muxed!) platform we have two types of GPIO - a
> > Synopsys controller which is a fairly conventional GPIO controller, then
> > a sigma-delta GPIO controller which can also do a an analogue type
> > output (as well as digital).
> 
> Does that mean it is really not a GPIO controller but a kind of D/A converter?

Kind of.  In the basic mode it's just a GPIO controller that does 
digital I/O.  In the SD mode it all really depends on what the external 
filter looks like.  As gpio_set_value() takes an int as the value, then 
the gpio controller theoretically _could_ treat that as an analogue 
output value and use the pinctrl api to set the converter and rate sizes 
but I don't really want to go there yet as it's a bit of an abuse of the 
gpio API!

> >  For lots of our pads they can either be
> > ARM GPIO, SD GPIO or some other function, so I don't see how this fits
> > in with a single GPIO base.
> 
> And each of them are modeled as a separate gpio_chip I guess?
> 
> Otherwise it's a bad match with reality. We had this discussion with GRant
> where two gpio_chips would use the same number range in the GPIO
> global pinspace, and it's basically not allowed IIRC.

Yes, the SD-GPIO isn't memory mapped so has a completely separte 
gpio_chip.

> But yes, there is an assumption that each pin controller will only
> deal with one block of GPIO pins. So if I make it possible to support
> several GPIO ranges for one pin controller, does that solve your problem?
> 
> Like this:
> 
> struct pinctrl_gpio_range {
>     char *name;
>     unsigned int base;
>     unsigned int npins;
> }
> 
> static unsigned int gpio_ranges[] = {
>     {
>         .name="chip1",
>         .base = 0,
>         .npins = 16,
>     },
>     {
>         .name =" chip2",
>         .base = 32,
>         .npins = 16,
>     },
>     {
>         .name = "chip3",
>         .base = 64,
>         .npins = 16,
>     },
> };
> 
> static struct pinctrl_desc foo_desc = {
>         ...
>         .gpio_ranges = gpio_ranges,
>         .num_gpio_ranges = ARRAY_SIZE(gpio_ranges),
> };
> 
> For three different 32-bit GPIO controllers muxed on
> pins 0..31 using GPIO space pins from 0..95.
> 
> Then I pass the number of the instance down to the
> driver in the gpio_request_enable() callback like
> this:
> 
> int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
> 	    unsigned instance,
> 	    unsigned offset);
> 
> Would this work?
> 
> This has a restriction: the GPIO space must be mapped in
> continous ranges, as must the pin controller. Else we need
> one entry per pin in the list above...

OK, that looks perfect!

> >> +The correspondence for the range from the GPIO subsystem to the pin controller
> >> +subsystem must be one-to-one. Thus the GPIO pins are in the pin controller
> >> +range [0 .. maxpin] where maxpin is the specified end of the pin range.
> >
> > So doesn't this mean that the enumeration that was initially described
> > as arbitrary actually has to enumerate the GPIO pins first?
> 
> If you use GPIO accessors, the enumeration has to match.
> So I rewrite it like this:
> 
> "this enumeration was arbitrarily chosen, in practice you need to think
> through your numbering system so that it matches the layout of registers
> and such things in your driver, or the code may become complicated. You must
> also consider matching of offsets to the GPIO ranges that may be handled by
> the pin controller."
> 
> OK?

Sounds good.

> >> +static struct class pinctrl_class = {
> >> +     .name = "pinctrl",
> >> +     .dev_release = pinctrl_dev_release,
> >> +     .dev_attrs = pinctrl_dev_attrs,
> >> +};
> >
> > Greg K-H has mentioned in the past that class is now deprecated for new
> > use and that a bus_type should be used instead.
> 
> Can you provide a reference with some detail?
> The pin control devices are usually aleady on a bus like the
> platform_bus or amba_bus or i2c_bus, then they register a
> class device in this case.
> 
> The kerneldoc documentation says
> "A bus is a channel between the processor and one or more devices."
> 
> This isn't the case here.
> 
> Anyhthing that help me understand this is appreciated, Arnd?

There's a thread here https://lkml.org/lkml/2011/3/25/443 where this has 
been discussed (I originally had a class too).

> >> +/**
> >> + * struct pinctrl_desc - pin controller descriptor, register this to pin
> >> + * control subsystem
> >> + * @name: name for the pin controller
> >> + * @pins: an array of pin descriptors describing all the pins handled by
> >> + *   this pin controller
> >> + * @npins: number of descriptors in the array, usually just ARRAY_SIZE()
> >> + *   of the pins field above
> >> + * @maxpin: since pin spaces may be sparse, there can he "holes" in the
> >> + *   pin range, this attribute gives the maximum pin number in the
> >> + *   total range. This should not be lower than npins for example,
> >> + *   but may be equal to npins if you have no holes in the pin range.
> >> + * @pmxops: pinmux operation vtable, if you support pinmuxing in your driver
> >> + * @gpio_base: the base offset of the pin range in the GPIO subsystem that
> >> + *   is handled by this controller, if applicable. This member is only
> >> + *   relevant if you want to e.g. control pins from the GPIO subsystem.
> >> + * @gpio_pins: the number of pins from (and including) the gpio_base offset
> >> + *   handled by this pin controller.
> >> + * @owner: module providing the pin controller, used for refcounting
> >> + */
> >> +struct pinctrl_desc {
> >> +     const char *name;
> >> +     struct pinctrl_pin_desc const *pins;
> >> +     unsigned int npins;
> >> +     unsigned int maxpin;
> >> +     struct pinmux_ops *pmxops;
> >> +     unsigned int gpio_base;
> >> +     unsigned int gpio_pins;
> >> +     struct module *owner;
> >
> > Would it be better to put the owner in the ops structure like file_ops?
> > I'm sure I remember someone saying that it's better to do that so that
> > it's in the modules .data/.rodata section but I can't find that
> > reference.
> 
> I can't do that because the pinmux_ops vtable is not mandatory.
> 
> The plan is to add more ops for other things like pin bias etc.

OK, I'd missed that.

> >> +/**
> >> + * struct pinctrl_dev - pin control class device
> >> + * @desc: the pin controller descriptor supplied when initializing this pin
> >> + *   controller
> >> + * @node: node to include this pin controller in the global pin controller list
> >> + * @dev: the device entry for this pin controller
> >> + * @owner: module providing the pin controller, used for refcounting
> >> + * @driver_data: driver data for drivers registering to the pin controller
> >> + *   subsystem
> >> + *
> >> + * This should be dereferenced and used by the pin controller core ONLY
> >> + */
> >> +struct pinctrl_dev {
> >> +     struct pinctrl_desc *desc;
> >> +     struct radix_tree_root pin_desc_tree;
> >> +     spinlock_t pin_desc_tree_lock;
> >> +     struct list_head node;
> >> +     struct device dev;
> >> +     struct module *owner;
> >> +     void *driver_data;
> >
> > Couldn't the struct device driver_data be used here?
> 
> I'm already using dev_set_drvdata(&pctldev->dev, pctldev);
> So I can retrieve the pctldev withdev_get_drvdata(dev);
> in sysfs...
> 
> If I wasn't registering sysfs nodes I couldv'e used it.

OK, fair enough.

> >> +/* These should only be used from drives */
> >
> > s/drives/drivers?
> 
> OK.
> 
> >> +/**
> >> + * struct pinmux_ops - pinmux operations, to be implemented by pin controller
> >> + * drivers that support pinmuxing
> >> + * @request: called by the core to see if a certain pin can be made available
> >> + *   available for muxing. This is called by the core to acquire the pins
> >> + *   before selecting any actual mux setting across a function. The driver
> >> + *   is allowed to answer "no" by returning a negative error code
> >> + * @free: the reverse function of the request() callback, frees a pin after
> >> + *   being requested
> >
> > So is the request like gpio_request() or just test if it the pin is
> > available?  If its the latter then perhaps pin_is_available() might be a
> > better name?
> 
> It's the former. The pin controller may have some electrical
> properties that makes it impossible to request a certain pin for muxing
> at a certain time. (Found out on earlier list review.)

OK, it's a bit of a language nitpick, but I interpreted that as meaning 
it was purely a test.

	@request: called by the core to reserve a pin for muxing. This 
	is called by the core to acquire the pins before selecting any 
	actual mux setting across a function. The driver is allowed to 
	answer "no" by returning a negative error code.

maybe makes things a little clearer (to me anyway!)?

> >> +#else /* !CONFIG_PINMUX */
> >> +
> >> +static inline int pinmux_request_gpio(unsigned gpio)
> >> +{
> >> +     return 0;
> >> +}
> >> +
> >> +static inline void pinmux_free_gpio(unsigned gpio)
> >> +{
> >> +}
> >> +
> >> +static inline struct pinmux *pinmux_get(struct device *dev, const char *func)
> >> +{
> >> +     return NULL;
> >> +}
> >
> > The CONFIG_PINMUX=y version of pinmux_get returns an ERR_PTR() encoded
> > error so perhaps this should return something like ERR_PTR(-ENXIO)?
> 
> No this is modeled more like the regulator stubs in
> <linux/regulator.h>. For example, if you're compiling for a
> platform that does not support regulators they are assumed to
> be always on.
> 
> In this case, if compiled for a platform without pinmux, we assume
> we got the pins we need already so it just works, not fail.

That makes perfect sense!  Doh!

Thanks a lot for doing this work Linus, it's really appreciated and 
looking great!  It's a bit difficult for me to test this on my platform 
at the moment as I'm still trying to handle all of the device tree stuff 
but I'll give this a good test as soon as I can.

Jamie



More information about the linux-arm-kernel mailing list