From owner-freebsd-hackers@FreeBSD.ORG Thu Jun 27 21:20:20 2013 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 7AE58B0E for ; Thu, 27 Jun 2013 21:20:20 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from bigwig.baldwin.cx (bigwig.baldwin.cx [IPv6:2001:470:1f11:75::1]) by mx1.freebsd.org (Postfix) with ESMTP id 534011F4A for ; Thu, 27 Jun 2013 21:20:20 +0000 (UTC) Received: from jhbbsd.localnet (unknown [209.249.190.124]) by bigwig.baldwin.cx (Postfix) with ESMTPSA id A7E9BB941; Thu, 27 Jun 2013 17:20:19 -0400 (EDT) From: John Baldwin To: freebsd-hackers@freebsd.org Subject: Re: Exposing driver's GPIOs through gpiobus Date: Thu, 27 Jun 2013 13:49:32 -0400 User-Agent: KMail/1.13.5 (FreeBSD/8.2-CBSD-20110714-p25; KDE/4.5.5; amd64; ; ) References: In-Reply-To: MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-Id: <201306271349.32203.jhb@freebsd.org> X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.7 (bigwig.baldwin.cx); Thu, 27 Jun 2013 17:20:19 -0400 (EDT) Cc: Ryan Stone X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Jun 2013 21:20:20 -0000 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