Exposing driver's GPIOs through gpiobus
John Baldwin
jhb at freebsd.org
Thu Jun 27 21:20:20 UTC 2013
On Wednesday, June 12, 2013 11:36:04 pm Ryan Stone wrote:
> At $WORK we have some custom boards with multi-port uarts managed by puc.
> The uart devices happen to provide some GPIOs, and our hardware designers
> have appropriated those GPIOs for various purposes entirely unrelated to
> the uart.
>
> I'm looking for a clean way to provide access to the GPIOs. It occurred to
> me that this was a problem that should be solved through newbus, and lo and
> behold I have discovered that FreeBSD provides a gpiobus driver that seems
> suitable. I've been playing around with this for a couple of days and I
> have a solutions that is working, but there are aspects that I am unhappy
> with. I also quite unfamiliar with newbus, so there easily could be better
> ways to approach the problem that I haven't thought of.
>
> What I ended up doing was making gpiobus and gpioc children of the puc
> bus. In puc_bfe_attach() I create two new child devices of the puc device
> with device_add_child(), one with the gpioc devclass and one with the
> gpiobus devclass. I then attach both children with
> device_probe_and_attach(). I make the puc_pci driver itself provide
> implementations of the various gpio methods (like gpio_pin_get) so they can
> be inherited by the child devices.
>
> Things start to get somewhat messy in the gpio client code. I have the
> same image running on many different hardware types, so I can't use device
> hints to create a child device of the gpiobus. Instead my kernel module
> tracks down the device_t for the puc, finds the gpiobus child, and uses
> BUS_ADD_CHILD to create a child of the gpiobus. I had to add a new gpiobus
> method to allocate GPIO pins to my driver instance. Once that's done, I
> can toggle GPIOs and whatnot using methods on my driver instance.
>
> The things that I'm most unhappy with (newbus-wise, anyway) are:
>
> 1) By default the gpioc and gpiobus drivers were claiming the uart children
> of the puc. I had to decrease their priority in bus_probe to
> BUS_PROBE_LOW_PRIORITY to work around the problem. I really don't think
> that was the right solution. I guess I could introduce a new device that
> is a child of the puc, make sure that it will not claim the uarts, and then
> make the gpioc and gpiobus children of this device.
>
> 2) I'm not sure how to clean up my child device when my module is
> unloaded. Currently I am checking if it already exists on load and reusing
> it if so. I may be missing something obvious here.
Just leave the device around and reuse it. In your identify routine do
something like this:
static void
agp_i810_identify(driver_t *driver, device_t parent)
{
if (device_find_child(parent, "agp", -1) == NULL &&
agp_i810_match(parent))
device_add_child(parent, "agp", -1);
}
>
> 3) I really don't like the way that I am adding my child to gpiobus. Upon
> writing this it occurs to me that device_identify would be the canonical
> way to do this. Previously it wasn't clear to me how to fit
> device_identify into the current architecture of the gpio client but I see
> how it can be done now.
Yes, device_identify is what you want. I think it will also solve problem 1
for you as well.
--
John Baldwin
More information about the freebsd-hackers
mailing list