Re: Question about GPIO Lib
Mark: On Wed, Feb 1, 2012 at 6:32 AM, Mark Brown wrote: > > Just to expand on this a bit: lots of people would prefer not to have a > userspace component at all due to the same hardware safety concerns that > you have, or to have the userspace component be a driver using gpiolib > which needs to be explicitly connected to the GPIOs. ... which I think is a spectacularly bad idea. :) Diversion from the original theme of this thread notwithstanding, I don't see the point in the additional complexity of implementing such a heavy-handed lockout when it's pretty darned easy to just do a gpio_request() in kernel space to take the pin entirely away from users. I do that pretty routinely, but then in the relevant kernel-side driver I almost always offer a sysfs attribute of my own that lets me grant users controlled access to the functionality provided by the pin. For example, if it's a RESET-type pin for an external chip, then I'll have a /sys/.../assert_reset attribute such that when root writes to it, my store() method sends a timed pulse to the physical GPIO pin. Or not, depending on what mood the device is in at the time--- which the driver always knows. I won't let the user kill anyone, of course, but I WILL grant them tools like the above to bring the platform under control and investigate problems during hardware integration. The productivity improvement more than offsets the thought and code investment required. I have often considered a gpiolib patch that just makes sysfs attributes read-only when kernel-side does a gpio_request(), rather than taking the pin attributes away entirely. That way I can have simple tools in userspace to silently log GPIO activity for troubleshooting. The blocking reads that some versions of gpiolib offer today make this work even better. b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Question about GPIO Lib
Bruce: On Mon, Jan 30, 2012 at 6:06 PM, wrote: > Bill Gatliff wrote on 01/27/2012 10:42:57 AM: >> Sounds like you DON'T want to merely export that GPIO pin to userspace. >> > > Well, yes I do want to just export to userspace I misunderstood your message, then. I was thinking that you were already using certain pins in kernel space, and didn't want THOSE pins exported to userspace due to the risks that users might invoke them and cause Bad Things to happen. > I just want to restrict > the pins that get exported to only those that are defined in the device > tree. I don't want or need to access any of the exported pins from kernel > space and I don't want user space to access any pin not explicitly called > out in the device tree. I want it to behave like gpio-leds only with > input as well as output capabilities. I glanced at gpiolib.c, and I don't immediately see a way to achieve this with the current code. Again, you could get the same net effect by doing a gpio_request() in kernel space on the pins you DON'T want exported, which would prevent those pins being exportable. But that's still different from what you are actually asking for. > If I understand this correctly you're basically saying that gpiolib is a > waste of time and I should just write my own driver? I'm DEFINITELY not saying that gpiolib is generally a waste of time! :) I'm just saying that, sadly, in many ways gpiolib is still a work-in-progress. The userspace component has been somewhat controversial in general over the years, and definitely lacks several key features in addition to the one you are asking for. Since I know others will ask :), note that the userspace component won't give you a direction attribute for pins whose directions cannot be changed from userspace. That's a pretty important omission, since it prevents me from conveniently verifying (apart from debugfs, I mean) that a pin is in fact configured in the direction I want it to be. Whether I can change its direction is a different issue entirely. Another omission that has struck me over the years is that it's not straightforward for gpio_chip authors to add custom attributes in sysfs for either the chip itself, or for the pins the chip exports. Within /sys/class/gpio/gpio/ I mean. But even in its current state, gpiolib is awesome. Maybe someday I or someone else will find time to make it awesomer. :) b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Question about GPIO Lib
Bruce: On Fri, Jan 27, 2012 at 5:31 AM, wrote: > > The problem is we've got a number of other things hooked up to the GPIO > pins that it would be very bad if someone from user space played with > them, like our FPGA configuration pin. Some one toggles that and our box > goes stupid. So what I'm wondering is if there's a way, preferably via > the device tree, to limit the GPIOs that GPIO Lib exposes to user space? Sounds like you DON'T want to merely export that GPIO pin to userspace. If you have anything in kernel space doing a gpio_request() on that pin, it won't be exportable to userspace anyway. Regardless, you are probably better off implement a DEVICE_ATTR that, in its store() method, treads lightly on said pin. And then do a gpio_request() in kernel space so that users can't ever see the pin directly. Just my $0.02. b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Question on supporting multiple HW versions with a single driver (warning: long post)
Guys: I think the Silicon Motion SM501 driver might provide a useful example, since the chip comes in both memory-mapped and PCI versions. Unfortunately the chip is implemented as a multi-function driver (mfd), so the code is not un-complicated. Still fairly straightforward and well-written once you learn your way around it, though. Basically, it implements a core set of functionality to talk to the actual chip registers, which is bus-agnostic. Then the bus-specific drivers use these functions when they actually want to touch the chip itself. In other words, exactly what David suggested. b.g. On Mon, Feb 7, 2011 at 8:37 PM, wrote: >> >> There are a number of drivers which already have this sort of dual bus >> binding. >> > > Thanks for the feedback David, I appreciate it. Could you point me to one > of those drivers that has "this sort of dual bus binding" so can see an > example of what I'm trying to do? > > Bruce > ___ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev > -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Xorg on Fujitsu "Lime" with MPC5200b?
Roman Fietze wrote: > Yes. I added a routine like > > /* Swap frame buffer bytes in 32 bit value. */ > static __inline unsigned int > fbbits_swap32(unsigned int __bsx) > { > return __bsx) & 0xff00) >> 8) | (((__bsx) & 0x00ff) << 8) | > (((__bsx) & 0xff00) >> 8) | (((__bsx) & 0x00ff) << 8)); > } > I baked the above code into shadowUpdatePacked(), and it didn't seem to help anything--- my icewm mouse cursor was still quite jagged, as was all the text on the screen (clock widget, etc). So I replaced the above code with a return 0, and the icewm desktop went completely black--- and everything else remained unchanged. Apparently, there are several similar modifications that need to be made, i.e. the shadowUpdatePacked() function isn't the only way to the framebuffer memory? I'm really looking forward to seeing your code, as I have no idea how to even identify the places that need hacking. I understand the utility of the hack, however. Makes me think that we're all just soldering this chip down to the wrong data lines, and makes me wonder if there isn't an "endianness bit" in the memory bus controller that can undo this damage for us. I know I've seen such a bit in other SoCs... Thanks! b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Xorg on Fujitsu "Lime" with MPC5200b?
Roman Fietze wrote: > Then I added void shadowUpdatePackedSwapped16() and > shadowUpdatePackedSwapped32() which I was using instead of the > original *Weak functions, which in turn uses the above swap routine > when copying from shadow to the device. > I'm not sure what the *Weak stuff is doing. Can I just hack shadowUpdatePacked() itself? b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Xorg on Fujitsu "Lime" with MPC5200b?
I would love it if you posted your code! Thanks!! b.g. On Apr 15, 2010 8:53 AM, "Roman Fietze" wrote: Hello Bill, On Thursday 15 April 2010 15:01:59 Bill Gatliff wrote: > Are you talking about this code here? > ... Yes. I added a routine like /* Swap frame buffer bytes in 32 bit value. */ static __inline unsigned int fbbits_swap32(unsigned int __bsx) { return __bsx) & 0xff00) >> 8) | (((__bsx) & 0x00ff) << 8) | (((__bsx) & 0xff00) >> 8) | (((__bsx) & 0x00ff) << 8)); } Then I added void shadowUpdatePackedSwapped16() and shadowUpdatePackedSwapped32() which I was using instead of the original *Weak functions, which in turn uses the above swap routine when copying from shadow to the device. If you want I can post (in the ML) or mail you the files that I changed. A diff probably won't help a lot, because I think we changed more than that, and we are using a pretty old XFree version. Roman -- Roman Fietze Telemotive AG Büro Mühlhausen Breitwiesen ... ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Xorg on Fujitsu "Lime" with MPC5200b?
Roman Fietze wrote: > Hallo Bill, > > On Thursday 15 April 2010 05:07:08 Bill Gatliff wrote: > > >> Actually, I *have* Debian squeeze's xorg running on the platform just >> fine, with a 2.6.34-rc1 kernel (kernel.org). Problem is, every single >> diagonal line is very blocky--- not smooth at all. >> > > I'm 95% sure it's an endianess problem, on our boards we had to modify > the X11 driver. What I did was swapping bytes when updating the device > from the shadowfb inside programs/Xserver/miext/shadow/shpacked.c > Are you talking about this code here? void shadowUpdatePacked (ScreenPtr pScreen, shadowBufPtr pBuf) { ... while (i--) *win++ = *sha++; Do I endian-swap each *sha? Or, do I reorder the sha array before dereferencing it (e.g. each *sha is right, but adjacent ones are in the wrong order)? b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Xorg on Fujitsu "Lime" with MPC5200b?
Guys: I'm not quite sure where to ask this question, but all my attempts elsewhere have come up short, so... Put simply, I have an MPC5200b platform with a Fujitsu "Lime" GDC, and I'm trying to run Debian squeeze's xorg on it. Actually, I *have* Debian squeeze's xorg running on the platform just fine, with a 2.6.34-rc1 kernel (kernel.org). Problem is, every single diagonal line is very blocky--- not smooth at all. I used to think this was a problem with X's fonts, but now I don't think so because the mouse cursor's diagonal lines also look equally bad. It's almost as if any time the platform tries to draw a diagonal line, truncation/rounding errors are causing it problems in figuring out which pixels to turn on and off. A non-Linux kernel on this hardware, running a non-X GUI, seems to work fine so I think the hardware isn't the problem. Anyone have any suggestions on where to start with this one? Anyone else running a similar configuration with any success? I'm completely lost, and running out of hair *fast*... Thanks! b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
kernel BUG at kernel/timer.c:643!
Is anyone seeing this message on an MPC5200 platform with the current HEAD from Linus Torvalds' git repo? I just did a rebase, and started seeing it... b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Paul Mundt wrote: > In some cases that might be valid, but there are many cases where drivers > can reconfigure their capability sets based on which GPIOs are and aren't > available. Just because a pin isn't available doesn't make it a > show-stopper for the probe path.. > Understood. I just tweaked my kernel to run all probe()s in their own kthreads. The results were a mixed bag, as expected. On the one hand, it's pretty cool to see everything running in parallel! On the other hand, I can see now yet another big reason why a probe free-for-all won't work. Busses are also devices, so there are plenty of places where a device for a particular bus type won't be able to probe because the target bus simply doesn't exist yet. That's yet another dependency that I hadn't thought about. Were I to rewrite Linux :), I would make probing parallel from the beginning. But I think I'm going to have to settle for now with kthreading my probes that might want to sleep, and adding a wait queue to gpio_request() and a few others. It ain't perfect, but it is achieveable. *sigh* b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Grant Likely wrote: > On Sat, Apr 10, 2010 at 5:39 PM, Paul Mundt wrote: > >> In cases where you can specifically note that dependencies, doing so will >> save you a world of pain. Despite that, it's simply not possible to do >> this as a free-for-all. Devices or busses that can tolerate multi-threaded >> probing need to be converted over one at a time, but even then you still >> need the dependency tracking for those that depend on link order today. >> Who's to say a function like gpio_request_wait_for_it(GPIO_NUMBER, "dependent-driver") isn't the way to do the dependency tracking? I can't even implement that without a context that can sleep... b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Paul Mundt wrote: > > In cases where you can specifically note that dependencies, doing so will > save you a world of pain. Despite that, it's simply not possible to do > this as a free-for-all. Devices or busses that can tolerate multi-threaded > probing need to be converted over one at a time, but even then you still > need the dependency tracking for those that depend on link order today. > Right now I'm thinking mostly about GPIO devices which need to register before things like gpio-leds can use them. Sometimes the GPIO expansion chip of interest is on i2c, other times it's spi, and still others it's a platform or USB device. Linking the gpio-led driver late helps that specific situation. But what about when I want to use a pin on a GPIO expansion device as the card-detect for an MMC slot? Or, as I've just recently noticed in one hardware platform I'm working on, using a pin on a SPI GPIO expander as a chip-select for another SPI device, but through gpiolib? Eventually, the dependencies don't become circular but changing the link order will break some and fix others. Ugh. Definitely, a free-for-all isn't going to work. But I don't think that having every driver do its own kthread_run() is a solution, either. I'll keep tinkering. :) b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Grant Likely wrote: > On Fri, Apr 9, 2010 at 1:23 PM, Bill Gatliff wrote: > >> Guys: >> >> >> My recent post, "Requesting a GPIO that hasn't been registered yet", and >> Anton's reply thereto (thanks, Anton!) on linuxppc-dev got me thinking >> about the problem of dependencies between devices in different classes, >> and/or between drivers/devices in general. I'd like to float an idea to >> see if it's worth pursuing. >> >> Changing the link order to get drivers to initialize in the right order >> will always be a problem for someone--- the order will be right for some >> people, but exactly wrong for others. And the problem is made worse for >> Device Tree-based systems, where just about everything including IRQ >> descriptors are created on a demand and/or as-available basis. What if >> we let the kernel sort those dependencies out for us, at runtime? I >> think it's possible, and I can't be the only one who would like to see >> this happen. >> >> There are two parts to my idea for a solution. First part is to modify >> do_initcalls() so that it launches each initcall function in its own >> kernel thread. Wait, don't panic yet! >> > > Is initcall the right granularity? Shouldn't it be that each .probe() > hook gets its own thread? Otherwise one device missing its resources > could block another device using the same driver (whose resources are > available) from probing. Good point, one that I missed. Yea, I guess I really want multithreaded probing. > Regardless, parallel probe has be attempted and failed before. There are > lots of fiddly bits to get right. > Yep. I wasnt aware of any specific attempts before, but I did suspect that there were fiddly bits lurking about. :) > In fact, there *used* to be code in the kernel that does exactly that. > It was put in 2.6.20, but removed in 2.6.21-rc1. Here's the relevant > commits, and a very interesting thread discussing the issues: > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=21c7f30b1d3f8a3de3128478daca3ce203fc8733 > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=5adc55da4a7758021bcc374904b0f8b076508a11 > http://lkml.indiana.edu/hypermail/linux/kernel/0705.1/0205.html > > It is pointed out in that thread that a big part of the problem is > that a large number of drivers in the tree just aren't safe for > multithreaded probing which is kind of a showstopper. Now, maybe > doing it at the initcall level makes it less scary and more sane, but > I suspect that it will still expose a lot of broken code that assumes > things are already set up because it has always been that way. > Yep. > Not quite the same model that you are talking about here, but it would > solve the problem on a per-driver basis. > Yea, but it's the per-driver part that I'm trying to avoid. > Have you dug into the Arjan's asynchronous function call infrastructure? > > http://lwn.net/Articles/314808/ > No, but I think I will now. :) b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Benjamin Herrenschmidt wrote: > On Fri, 2010-04-09 at 14:23 -0500, Bill Gatliff wrote: > >> My recent post, "Requesting a GPIO that hasn't been registered yet", and >> Anton's reply thereto (thanks, Anton!) on linuxppc-dev got me thinking >> about the problem of dependencies between devices in different classes, >> and/or between drivers/devices in general. I'd like to float an idea to >> see if it's worth pursuing. >> > > I'd rather do things a bit more explicitely and less prone to break > existing stuff... something along the lines of, first defining a variant > of the initcalls to enable that "multithreaded" stuff, along with an > explicit wait_for_service("subsys:hid"); for example. > > One could also expose service deps via the module info, thus delaying > module init, or things like that (in fact, initcalls could even come > with a list of dependencies). > The general problem with your approach is that the module in question might not know what services it needs to wait for. Specific to my situation, the gpio-led code doesn't have any way of knowing that it needs to wait until my pca953x i2c devices have all been installed so that the gpio pin I have specified even exists. And short of setting up some kind of table in the board-specific code (or device tree, actually), I don't know how to communicate such a dependency without touching the generic gpio-led code--- which I'm trying to avoid. I just want gpio-led to try again if the gpio pin it has been provided can't be requested yet. And I can see the need for similar behavior in several other of my drivers, hence the desire to generalize things a bit. I'm pretty sure my approach is only half-baked, but it does seem to avoid the need to touch a bunch of existing code--- especially to add board-specific dependencies. It just give the system a tool to sort things out on its own. I do think your overall criticism is valid, though. b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Bill Gatliff wrote: > > ... and kset_register() might be the only place that calls > wake_up_interruptible(). Wow. > Wow, indeed. With just the attached patch, I get exactly one OOPS now--- in ssc_free(), which I think is getting called because atmel_ssc_modinit() is racing with something. I wasn't able to get all the way to mounting my NFS rootfs, I think because I'm getting to ip_auto_config() before my ethernet controller has registered! :) $ git diff lib/kobject.c diff --git a/lib/kobject.c b/lib/kobject.c index b512b74..e75556c 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -18,6 +18,10 @@ #include #include +#include +#include +DECLARE_WAIT_QUEUE_HEAD(kset_wait); + /* * populate_dir - populate directory with attributes. * @kobj: object we're working on. @@ -721,6 +725,7 @@ int kset_register(struct kset *k) if (err) return err; kobject_uevent(&k->kobj, KOBJ_ADD); + wake_up_interruptible(&kset_wait); return 0; } @@ -744,7 +749,7 @@ void kset_unregister(struct kset *k) * looking for a matching kobject. If matching object is found * take a reference and return the object. */ -struct kobject *kset_find_obj(struct kset *kset, const char *name) +struct kobject *__kset_find_obj(struct kset *kset, const char *name) { struct kobject *k; struct kobject *ret = NULL; @@ -760,6 +765,14 @@ struct kobject *kset_find_obj(struct kset *kset, const char *name) return ret; } +struct kobject *kset_find_obj(struct kset *kset, const char *name) +{ + struct kobject *ret = NULL; + wait_event_interruptible(kset_wait, (ret = __kset_find_obj(kset, name))); + return ret; +} + static void kset_release(struct kobject *kobj) { struct kset *kset = container_of(kobj, struct kset, kobj); b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Bill Gatliff wrote: > Maybe there are fewer places that would need wait queues than I > originally thought! At least for drivers that use the device API, > kset_find_obj() might be the only place that needs to wait until a > device or bus appears. ... and kset_register() might be the only place that calls wake_up_interruptible(). Wow. b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: A better way to sequence driver initialization?
Bill Gatliff wrote: > If someone doesn't tell me this is a stupid idea, I might post it to > lkml. Now's your chance! :) > So I went ahead and tried it anyway: $ git diff init/main.c diff --git a/init/main.c b/init/main.c index dac44a9..1461d09 100644 --- a/init/main.c +++ b/init/main.c @@ -753,7 +753,11 @@ static void __init do_initcalls(void) initcall_t *fn; for (fn = __early_initcall_end; fn < __initcall_end; fn++) +#if 1 + kthread_run(do_one_initcall, *fn, "do_initcalls"); +#else do_one_initcall(*fn); +#endif /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work(); Interestingly, things didn't blow up as quickly as I had expected they would. :) Booting with initcall_debug=1 both with and without the kthread_run() mod has proven insightful. The first OOPS I get with the mod looks like this: ... calling ch_init+0x0/0x18 @ 325 Unable to handle kernel NULL pointer dereference at virtual address pgd = c0004000 [] *pgd= Internal error: Oops: 5 [#4] PREEMPT last sysfs file: Modules linked in: CPU: 0 Tainted: GD (2.6.33-rc5-csb737-00010-gaba040a-dirty #59) PC is at kset_find_obj+0x18/0x98 LR is at kset_find_obj+0x18/0x98 pc : [] lr : [] psr: 2013 sp : c3937f68 ip : c3937f68 fp : r10: r9 : r8 : r7 : c0396a6f r6 : r5 : 0005 r4 : c03f03b0 r3 : 0003 r2 : c3936000 r1 : r0 : 0001 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 0005317f Table: 20004000 DAC: 0017 Process do_initcalls (pid: 325, stack limit = 0xc3936270) Stack: (0xc3937f68 to 0xc3938000) 7f60: c03fc050 c03f03b0 0005 c03f03b0 c01c471c 7f80: c03f03b0 0005 c001e62c c024007c 1b58d32c 7fa0: 0005 c002c39c c381bfac c001e62c 1b58d32c 0005 c3937fd4 7fc0: c381bfac c001e62c c002c340 c005cb3c c3937fd8 c3937fd8 7fe0: c002df78 [] (kset_find_obj+0x18/0x98) from [] (driver_register+0x88/0x150) [] (driver_register+0x88/0x150) from [] (__hid_register_driver+0x38/0x70) [] (__hid_register_driver+0x38/0x70) from [] (do_one_initcall+0x5c/0x1c4) [] (do_one_initcall+0x5c/0x1c4) from [] (kthread+0x78/0x80) [] (kthread+0x78/0x80) from [] (kernel_thread_exit+0x0/0x8) Code: e24dd004 e3a1 e1a07001 ebfaf76c (e5963000) ---[ end trace f9bb68fd55862436 ]--- note: do_initcalls[325] exited with preempt_count 1 ... There is a ch_init() function in drivers/hid/hid-cherry.c. I think that function is calling hid_register_driver() before hid_init() has set up hid_bus_type. That causes kset_find_obj() to die because the kset structure it gets passed in ch_init() refers to a bus that doesn't exist yet. It's a plain 'ole initialization race. Maybe there are fewer places that would need wait queues than I originally thought! At least for drivers that use the device API, kset_find_obj() might be the only place that needs to wait until a device or bus appears. If I get a second next week, I might hack one in there and see how much farther I get... b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
A better way to sequence driver initialization?
Guys: My recent post, "Requesting a GPIO that hasn't been registered yet", and Anton's reply thereto (thanks, Anton!) on linuxppc-dev got me thinking about the problem of dependencies between devices in different classes, and/or between drivers/devices in general. I'd like to float an idea to see if it's worth pursuing. Changing the link order to get drivers to initialize in the right order will always be a problem for someone--- the order will be right for some people, but exactly wrong for others. And the problem is made worse for Device Tree-based systems, where just about everything including IRQ descriptors are created on a demand and/or as-available basis. What if we let the kernel sort those dependencies out for us, at runtime? I think it's possible, and I can't be the only one who would like to see this happen. There are two parts to my idea for a solution. First part is to modify do_initcalls() so that it launches each initcall function in its own kernel thread. Wait, don't panic yet! Second, we create/modify functions like gpio_request() so that if they fail, they can optionally stop in a wait queue until the call could succeed. Then gpiochip_add() would signal that queue each time a new gpiochip was added. Functions like request_irq() and clk_get()--- and probably many others--- would do the same thing, but with their own wait queues. Something like this: static wait_queue_head_t requestor_wq; int gpiochip_add(struct gpio_chip *chip) { ... wake_up_interruptible(&requestor_wq); return status; } int gpio_request_wait(unsigned gpio, const char *label) { return wait_event_interruptible(&requestor_wq, !gpio_request(gpio, label)); } Or we might want to make the above code be the actual gpio_request(), and bury the wait_event_interruptible() inside of that. Doing so would prevent having to touch a lot of code, but would definitely change the behavior of gpio_request(). Not sure which approach is best. Finally, I think that do_initcalls() would turn into something like this: static void __init do_initcalls(void) { initcall_t *fn; for (fn = __early_initcall_end; fn < __initcall_end; fn++) kthread_create(do_one_initcall, *fn, "do_initcalls"); flush_scheduled_work(); } If someone doesn't tell me this is a stupid idea, I might post it to lkml. Now's your chance! :) b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Requesting a GPIO that hasn't been registered yet
Guys: I'm sure this is a FAQ, but I can't seem to find the answer. I'm happy to RTFM, if someone can please tell me where the FM is. :) I'm adding device table support to gpio_keys. The target is an MPC5200B. I have statements in my dts file that look like this: ... i...@3d40 { #address-cells = <1>; #size-cells = <0>; compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c"; reg = <0x3d40 0x40>; interrupts = <2 16 0>; ... lext60: max7...@60 { compatible = "maxim,max7314","phillips,pca953x"; reg = <0x60>; gpio-controller; #gpio-cells = <2>; }; }; ... gpio-keys { compatible = "gpio-keys"; encoder_button { gpios = <&lext60 12 0>; code = <28>; type = <1>; active-low = <0>; wakeup = <0>; debounce-interval = <0>; rep = <0>; }; }; In other words, the GPIO pin I'm using for the key is one of the bits on my pca953x GPIO expander chip. The above would all be great, except that I haven't come up with a way to make sure that my encoder_button doesn't try to probe before lext60 is available. In fact, I'm consistently getting initialization in the wrong order! Eventually the GPIO expander chip gets plugged in, because I can see it show up in sysfs. And what's really odd is, I recently made similar mods to gpio_leds and they are working fine--- although the GPIO pin is on a pca953x at address 20, instead of 60. I'm at a loss to explain why one works, but the other doesn't. And I don't know how to really fix this problem for good! Any suggestions? Thanks!! b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Sleep-capable GPIO slave-selects on MPC52xx?
Bill Gatliff wrote: > > It looks like the current version of the MPC52xx SPI driver won't work > with sleep-capable GPIOs for slave-selects. In particular, it looks > like mpc52xx_spi_fsmstate_transfer() is an interrupt handler that calls > mpc52xx_spi_chipsel(), which itself calls gpio_set_value(). Or, at > least my kernel thinks so, since I get a barrage of oops-type output > screaming at me whenever I hit the SPI device. :) > > Am I missing something, or is this a known (or at least now-identified) > limitation of the current mpc52xx_spi.c? > So, nobody has any feedback on this? :) Would using a threaded handler for the SPI interrupts be likely to work here? b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Sleep-capable GPIO slave-selects on MPC52xx?
Guys: A platform I have inherited utilizes a GPIO on an I2C expander chip (MAX7314) as a SPI slave-select. I'm using the actual MPC52xx SPI peripheral, not a PSC. It looks like the current version of the MPC52xx SPI driver won't work with sleep-capable GPIOs for slave-selects. In particular, it looks like mpc52xx_spi_fsmstate_transfer() is an interrupt handler that calls mpc52xx_spi_chipsel(), which itself calls gpio_set_value(). Or, at least my kernel thinks so, since I get a barrage of oops-type output screaming at me whenever I hit the SPI device. :) Am I missing something, or is this a known (or at least now-identified) limitation of the current mpc52xx_spi.c? Thanks! b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 0/2] Create an of_i2c_gpiochip_add()
Wolfram Sang wrote: >> Does the lack of response mean I'll be seeing these in an upcoming >> kernel release? I'd like to, because then I could more easily push >> > > As long as nobody said "I picked it up", it will probably not. Patches > regarding GPIO sometimes need a bit of time. Also, of_platform was in the > discussion of being removed, this might complicate things, too. > Is this the right mailing list for such patches, though? b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 0/2] Create an of_i2c_gpiochip_add()
Bill Gatliff wrote: > This patch series creates an of_i2c_gpiochip_add() function, to allow > i2c-based GPIO expanders to work with device tree gpio specifications. > So nobody has any yays or nays on this? I was expecting at least _something_! :) Does the lack of response mean I'll be seeing these in an upcoming kernel release? I'd like to, because then I could more easily push through related updates to a few i2c device drivers that I have in my local repo. b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: How to set GPIO state in the dts or in platform
Ayman El-Khashab wrote: > On 1/5/2010 10:38 PM, Bill Gatliff wrote: >> Ayman El-Khashab wrote: >> >>> I've got a custom board akin to the walnut. I've successfully got >>> u-boot, >>> the kernel, and a working filesystem. The only thing I lack is a >>> clear idea >>> of how to set a GPIO. >>> >> >> Isn't that the "flags" parameter, e.g.: >> >> gpios = >> >> ? >> >> If you are passing a 0 for the flags, try a 1. I know of at least one >> driver that interprets that to mean a polarity inversion. Maybe you'll >> get lucky. :) >> >> > Possibly, I saw that in the documentation directory, but didn't quite > follow the explanation that > was given. Below is what I was using as a reference, but is it as > simple as that? Do the flags encode > just the state or also, the open drain, hi-z and everything else? In > my case, I want the GPIO 3 actively > driven high. The flags can encode everything, or nothing. It all depends on what the caller of of_get_gpio_flags() does with them. (Note that I'm not an authority on this topic, I'm just telling what I've learned about it recently). For example, in of_mpc8xxx_spi_get_chipselects(), the flag is tested against OF_GPIO_ACTIVE_LOW, and the result is passed to gpio_direction_output() as the initial value. So it both inverts the sense of the pin, and sets its initial state. In of_gpio_leds_probe(), the flag is tested against OF_GPIO_ACTIVE_LOW as well. In both of the above examples, the drivers can make assumptions about things like the pin must be an output, will be actively driven in either direction, and so on. The convention is for the flag to be a bitmap of values from the of_gpio_flags enumeration, but the only value there is--- you guessed it--- OF_GPIO_ACTIVE_LOW. :) If you provide your own xlate() function in a of_gpio_chip driver, you can make the flags mean anything you want. As for anywhere you call of_gpio_get_flags(). For now, the only established interpretation is the OF_GPIO_ACTIVE_LOW one. b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: How to set GPIO state in the dts or in platform
Ayman El-Khashab wrote: > I've got a custom board akin to the walnut. I've successfully got > u-boot, > the kernel, and a working filesystem. The only thing I lack is a > clear idea > of how to set a GPIO. Isn't that the "flags" parameter, e.g.: gpios = ? If you are passing a 0 for the flags, try a 1. I know of at least one driver that interprets that to mean a polarity inversion. Maybe you'll get lucky. :) b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 0/2] *** SUBJECT HERE ***
Bill Gatliff wrote: > *** BLURB HERE *** > Dangit, sometimes I really hate it when emacs leaves its backup files around... :( Like now, for example. Please disregard the noise generated by my careless use of filename wildcards... b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC/PATCH 0/2] Updates to improve device tree support
This patch series updates the pca953x GPIO driver to take advantage of the new of_i2c_gpiochip_add() function, which registers i2c GPIO devices with the device tree API. These changes allow i2c-based GPIO expanders to be properly referenced from the proper entries in a device tree. The of_i2c_gpiochip_add() function has been posted for review on the linuxppc-dev mailing list. Bill Gatliff (2): Use struct of_i2c_gpio_chip instead of raw struct gpio_chip Reorder initialization to better support device tree data drivers/gpio/pca953x.c | 168 +--- 1 files changed, 88 insertions(+), 80 deletions(-) ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/2] Reorder initialization to better support device tree data
This patch changes the initialization sequence implemented in pca953x_probe(), so as to simplify the retrieval of device tree data when device trees are used. Incorporates the new of_i2c_gpiochip_add() function to register the newly-added GPIOs. Signed-off-by: Bill Gatliff --- drivers/gpio/pca953x.c | 130 +-- 1 files changed, 58 insertions(+), 72 deletions(-) diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 9c70963..3a20e2f 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -3,6 +3,7 @@ * * Copyright (C) 2005 Ben Gardner * Copyright (C) 2007 Marvell International Ltd. + * Copyright (C) 2010 Bill Gatliff * * Derived from drivers/i2c/chips/pca9539.c * @@ -53,13 +54,13 @@ static const struct i2c_device_id pca953x_id[] = { MODULE_DEVICE_TABLE(i2c, pca953x_id); struct pca953x_chip { - unsigned gpio_start; uint16_t reg_output; uint16_t reg_direction; + uint16_t reg_invert; struct gpio_chip *gpio_chip; struct i2c_client *client; - struct pca953x_platform_data *dyn_pdata; + struct pca953x_platform_data *pdata; char **names; #ifdef CONFIG_OF_GPIO @@ -214,7 +215,6 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->set = pca953x_gpio_set_value; gc->can_sleep = 1; - gc->base = chip->gpio_start; gc->ngpio = gpios; gc->label = chip->client->name; gc->dev = &chip->client->dev; @@ -222,119 +222,107 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->names = chip->names; } -/* - * Handlers for alternative sources of platform_data - */ #ifdef CONFIG_OF_GPIO -/* - * Translate OpenFirmware node properties into platform_data - */ -static struct pca953x_platform_data * -pca953x_get_alt_pdata(struct i2c_client *client) +static int __devinit pca953x_get_of_pdata(struct pca953x_chip *chip) { - struct pca953x_platform_data *pdata; struct device_node *node; const uint16_t *val; - node = dev_archdata_get_node(&client->dev.archdata); - if (node == NULL) - return NULL; + node = dev_archdata_get_node(&chip->client->dev.archdata); + if (!node) + return -EINVAL; - pdata = kzalloc(sizeof(struct pca953x_platform_data), GFP_KERNEL); - if (pdata == NULL) { - dev_err(&client->dev, "Unable to allocate platform_data\n"); - return NULL; - } - - pdata->gpio_base = -1; - val = of_get_property(node, "linux,gpio-base", NULL); - if (val) { - if (*val < 0) - dev_warn(&client->dev, -"invalid gpio-base in device tree\n"); - else - pdata->gpio_base = *val; - } + chip->gpio_chip->base = -1; + chip->i2c_gc.of_gc.gpio_cells = 2; val = of_get_property(node, "polarity", NULL); if (val) - pdata->invert = *val; + chip->reg_invert = *val; - return pdata; + return 0; } -#else -static struct pca953x_platform_data * -pca953x_get_alt_pdata(struct i2c_client *client) + +static int __devinit pca953x_gpiochip_add(struct pca953x_chip *chip) { - return NULL; + struct device_node *node; + node = dev_archdata_get_node(&chip->client->dev.archdata); + return of_i2c_gpiochip_add(node, &chip->i2c_gc); } #endif +static int __devinit pca953x_get_pdata(struct pca953x_chip *chip) +{ + struct pca953x_platform_data *pdata; + + pdata = dev_get_platdata(&chip->client->dev); + if (!pdata) + return -EINVAL; + + chip->pdata = pdata; + chip->gpio_chip->base = pdata->gpio_base; + chip->reg_invert = pdata->invert; + + return 0; +} + static int __devinit pca953x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pca953x_platform_data *pdata; struct pca953x_chip *chip; int ret; chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; + chip->client = client; #ifdef CONFIG_OF_GPIO chip->gpio_chip = &chip->i2c_gc.of_gc.gc; + if (!dev_get_platdata(&client->dev)) + pca953x_get_of_pdata(chip); #else chip->gpio_chip = &chip->gc; -#endif - - pdata = client->dev.platform_data; - if (pdata == NULL) { - pdata = pca953x_get_alt_pdata(client); - /* -* Unlike normal platform_data, this is allocated -* dynamically and must be freed
[PATCH 1/2] Use struct of_i2c_gpio_chip instead of raw struct gpio_chip
This patch is the first in a series that improves the pca953x driver's support for CONFIG_OF_GPIO a.k.a. device trees. It modifies the driver's chip structure definition to use a struct gpio_chip contained in a struct of_i2c_gpio_chip when CONFIG_OF_GPIO is set. If OF_GPIO is not used, an ordinary struct gpio_chip is employed. Signed-off-by: Bill Gatliff --- drivers/gpio/pca953x.c | 50 ++- 1 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index b097043..9c70963 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -56,18 +56,34 @@ struct pca953x_chip { unsigned gpio_start; uint16_t reg_output; uint16_t reg_direction; + struct gpio_chip *gpio_chip; struct i2c_client *client; struct pca953x_platform_data *dyn_pdata; - struct gpio_chip gpio_chip; char **names; + +#ifdef CONFIG_OF_GPIO + struct of_i2c_gpio_chip i2c_gc; +#else + struct gpio_chip gc; +#endif }; +static inline struct pca953x_chip *to_pca953x_chip(struct gpio_chip *gc) +{ +#ifdef CONFIG_OF_GPIO + return container_of(gc, struct pca953x_chip, i2c_gc.of_gc.gc); +#else + return container_of(gc, struct pca953x_chip, gc); +#endif +} + + static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) { int ret; - if (chip->gpio_chip.ngpio <= 8) + if (chip->gpio_chip->ngpio <= 8) ret = i2c_smbus_write_byte_data(chip->client, reg, val); else ret = i2c_smbus_write_word_data(chip->client, reg << 1, val); @@ -84,7 +100,7 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) { int ret; - if (chip->gpio_chip.ngpio <= 8) + if (chip->gpio_chip->ngpio <= 8) ret = i2c_smbus_read_byte_data(chip->client, reg); else ret = i2c_smbus_read_word_data(chip->client, reg << 1); @@ -104,7 +120,7 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) uint16_t reg_val; int ret; - chip = container_of(gc, struct pca953x_chip, gpio_chip); + chip = to_pca953x_chip(gc); reg_val = chip->reg_direction | (1u << off); ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); @@ -122,7 +138,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, uint16_t reg_val; int ret; - chip = container_of(gc, struct pca953x_chip, gpio_chip); + chip = to_pca953x_chip(gc); /* set output level */ if (val) @@ -152,7 +168,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) uint16_t reg_val; int ret; - chip = container_of(gc, struct pca953x_chip, gpio_chip); + chip = to_pca953x_chip(gc); ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val); if (ret < 0) { @@ -172,7 +188,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) uint16_t reg_val; int ret; - chip = container_of(gc, struct pca953x_chip, gpio_chip); + chip = to_pca953x_chip(gc); if (val) reg_val = chip->reg_output | (1u << off); @@ -190,7 +206,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) { struct gpio_chip *gc; - gc = &chip->gpio_chip; + gc = chip->gpio_chip; gc->direction_input = pca953x_gpio_direction_input; gc->direction_output = pca953x_gpio_direction_output; @@ -265,6 +281,12 @@ static int __devinit pca953x_probe(struct i2c_client *client, if (chip == NULL) return -ENOMEM; +#ifdef CONFIG_OF_GPIO + chip->gpio_chip = &chip->i2c_gc.of_gc.gc; +#else + chip->gpio_chip = &chip->gc; +#endif + pdata = client->dev.platform_data; if (pdata == NULL) { pdata = pca953x_get_alt_pdata(client); @@ -306,13 +328,13 @@ static int __devinit pca953x_probe(struct i2c_client *client, goto out_failed; - ret = gpiochip_add(&chip->gpio_chip); + ret = gpiochip_add(chip->gpio_chip); if (ret) goto out_failed; if (pdata->setup) { - ret = pdata->setup(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); + ret = pdata->setup(client, chip->gpio_chip->base, + chip->gpio_chip->ngpio, pdata->context); if (ret < 0) dev_warn(&client->dev, "setup failed, %d\n", ret); } @@ -333,8 +355,8 @@ static int pca953x_remove(struct i2c_client *client) int ret = 0;
[PATCH 0/2] *** SUBJECT HERE ***
*** BLURB HERE *** Bill Gatliff (2): Use struct of_i2c_gpio_chip instead of raw struct gpio_chip Reorder initialization to better support device tree data drivers/gpio/pca953x.c | 168 +--- 1 files changed, 88 insertions(+), 80 deletions(-) ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 1/2] Create a struct of_i2c_gpio_chip, for i2c-based GPIO devices
Signed-off-by: Bill Gatliff --- include/linux/of_gpio.h | 23 +++ 1 files changed, 23 insertions(+), 0 deletions(-) diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index fc2472c..0c39242 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -102,4 +102,27 @@ static inline int of_get_gpio(struct device_node *np, int index) return of_get_gpio_flags(np, index, NULL); } + + + +/* + * OF GPIO chip for I2C-based devices + */ +struct of_i2c_gpio_chip { + struct of_gpio_chip of_gc; +}; + +static inline struct of_i2c_gpio_chip *to_of_i2c_gpio_chip(struct gpio_chip *gc) +{ + struct of_gpio_chip *of_gc = to_of_gpio_chip(gc); + + return container_of(of_gc, struct of_i2c_gpio_chip, of_gc); +} + +extern int of_i2c_gpiochip_add(struct device_node *np, + struct of_i2c_gpio_chip *gc); + + + + #endif /* __LINUX_OF_GPIO_H */ -- 1.6.5 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 0/2] Create an of_i2c_gpiochip_add()
This patch series creates an of_i2c_gpiochip_add() function, to allow i2c-based GPIO expanders to work with device tree gpio specifications. Bill Gatliff (2): Create a struct of_i2c_gpio_chip, for i2c-based GPIO devices Create an of_i2c_gpiochip_add() drivers/of/gpio.c | 55 +++ include/linux/of_gpio.h | 23 +++ 2 files changed, 78 insertions(+), 0 deletions(-) ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/2] Create an of_i2c_gpiochip_add()
Signed-off-by: Bill Gatliff --- drivers/of/gpio.c | 55 + 1 files changed, 55 insertions(+), 0 deletions(-) diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 6eea601..56b438a 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -217,3 +217,58 @@ err0: return ret; } EXPORT_SYMBOL(of_mm_gpiochip_add); + +/** + * of_i2c_gpiochip_add - Add memory I2C-based GPIO chip + * @np:device node of the GPIO chip + * @gc:pointer to the of_i2c_gpio_chip allocated structure + * + * To use this function you should allocate and fill gc with: + * + * 1) In the gpio_chip structure: + *- all the callbacks + * + * 2) In the of_gpio_chip structure: + *- gpio_cells + *- xlate callback (optional) + * + * If succeeded, this function will do something useful... + */ +int of_i2c_gpiochip_add(struct device_node *np, + struct of_i2c_gpio_chip *i2c_gc) +{ + int ret = -ENOMEM; + struct of_gpio_chip *of_gc = &i2c_gc->of_gc; + struct gpio_chip *gc = &of_gc->gc; + + gc->label = kstrdup(np->full_name, GFP_KERNEL); + if (!gc->label) + goto err0; + + gc->base = -1; + + if (!of_gc->xlate) + of_gc->xlate = of_gpio_simple_xlate; + + np->data = of_gc; + + ret = gpiochip_add(gc); + if (ret) + goto err2; + + /* We don't want to lose the node and its ->data */ + of_node_get(np); + + pr_debug("%s: registered as generic GPIO chip, base is %d\n", +np->full_name, gc->base); + return 0; +err2: + np->data = NULL; +err1: + kfree(gc->label); +err0: + pr_err("%s: GPIO chip registration failed with status %d\n", + np->full_name, ret); + return ret; +} +EXPORT_SYMBOL(of_i2c_gpiochip_add); -- 1.6.5 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Trouble specifying dts gpio-leds with GPIO expander chip
Anton Vorontsov wrote: > Though, soon there will be an easier way to register I2C/SPI chips > with the OF GPIO infrastructure. > Should this make me hesitate to update the pca953x driver, or clone it? b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Question on MPC52xx IRQ[123] pins
Grant Likely wrote: > Correct. IRQ2 can only be used as IRQ2. It cannot be used a GPIO. > (Well, I suppose you *could* try to hack into the interrupt controller > driver and fetch the pin state that way; but I don't know if you can > read the state of masked out IRQ pins, and it sure would be ugly.) > Actually, I did think of a way you could do this. You could register an interrupt handler on the line, and set the irq type to level-low or level-high. Depending on whether the handler fires right away, you know what the state of the pin must be. And when the interrupt handler does fire, you switch the irq type to the opposite setting. I think that approach rates pretty high on the "ugly scale" too, but perhaps tolerably so. In fact, were I to actually need to interface one of the IRQ lines to gpiolib, I might attempt this... b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 1/1] Adds gpio_to_irq() and related support to the mpc52xx_gpio WKUP peripheral driver
Bill Gatliff wrote: > Second, the previously-unimplemented gpio_to_irq() function was added, > using __gpio_to_irq(). The author does not know why this code was previously > left out of arch/powerpc/include/asm/gpio.h. It seems to work. The generic > irq_to_gpio() function was not tested. > Actually, I just noticed that this patch was already committed but I hadn't pulled it in to my repo so I ended up re-discovering and duplicating it. The rest of the comments for this patch are accurate. b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 1/1] Adds gpio_to_irq() and related support to the mpc52xx_gpio WKUP peripheral driver
This patch cascades the GPIO_WKUP peripheral's eight pins into separate, virtual interrupt descriptors. This demultiplexing relieves driver authors of having to demultiplex and manage the pins on their own. Several important changes were necessary to implement this support, beyond just the addition of the cascading and irq_host functions. First, the gpiochip devices are now registered during arch_initcall. Without this modification, the virtual interrupt mapping changes during startup in ways that cause drivers to "lose" their interrupt-to-handler mappings. The mpc52xx FEC driver, for example, will fail to receive interrupts if the gpiochip and irq_host registrations happen at subsys_initcall as was done in the previous version of the driver. Second, the previously-unimplemented gpio_to_irq() function was added, using __gpio_to_irq(). The author does not know why this code was previously left out of arch/powerpc/include/asm/gpio.h. It seems to work. The generic irq_to_gpio() function was not tested. Finally, the interrupt-controller property was added to the mpc52xx_gpio device tree entry for the WKUP peripheral. The interrupt demultiplexing code is installed only when this property is present. The author's device tree node for the GPIO_WKUP peripheral looks like this: gpio_wkup: g...@c00 { compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup"; #gpio-cells = <2>; #address-cells = <0>; reg = <0xc00 0x40>; interrupt-parent = <&mpc5200_pic>; interrupts = <1 8 0 0 3 0>; gpio-controller; interrupt-controller; #interrupt-cells = <3>; }; The author generally refrains from modifying working code. However, there were a large number of redundant statements in the existing gpiolib implementation code to compute bit masks for pins, and these masks needed to be consistent throughout the gpio and interrupt cascading implementation. The redundant statements were replaced with a new mpc52xx_wkup_gpio_to_mask() helper function. The gpio-to-irq mapping follows the convention established by the gpiolib driver. Specifically, gpio pin 0 is GPIO_WKUP_7, pin 1 is GPIO_WKUP_6, and so on. An example of a device tree node that attaches to GPIO_WKUP_7 looks like this (the associated driver is a modified version of the existing drivers/misc/input/rotary_encoder.c): rotary-encoder { compatible = "linux,rotary-encoder","rotary-encoder"; interrupts = <&mpc5200_pic 1 2 3>; gpios = <&gpio_wkup 0 0>; type = <1>; val-ccw = <0x4a>; val-cw = <78>; }; The three values in the "gpios =" statement are the phandle for the gpio controller, the peripheral pin number, and a flag that is currently ignored. The rotary-encoder driver uses of_get_gpio_flags() to get the gpiolib value for the pin: cfg->gpio[wchan] = of_get_gpio_flags(ofdev->node, ngpio++, NULL); The value returned by of_get_gpio_flags() can be passed to gpio_to_irq(), and then on to request_irq(). The GPIO_WKUP peripheral supports limited options for interrupt types, including: IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_BOTH The driver emulates IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_LEVEL_HIGH types using falling and rising edges, respectively, but this code has not been extensively tested. The GPIO_WKUP peripheral's "pulse" interrupt type is not supported. This driver does not currently support Deep Sleep wakeups, only non-Deep Sleep ones. The Deep Sleep wakeups appear to be most suited for support under power management functionality, and not gpio-related operations. Signed-off-by: Bill Gatliff --- arch/powerpc/platforms/52xx/mpc52xx_gpio.c | 328 ++- 1 files changed, 267 insertions(+), 61 deletions(-) diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c index 2b8d8ef..67d91d2 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c @@ -1,6 +1,7 @@ /* * MPC52xx gpio driver * + * Copyright (c) 2010 Bill Gatliff * Copyright (c) 2008 Sascha Hauer , Pengutronix * * This program is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -34,8 +36,18 @@ struct mpc52xx_gpiochip { unsigned int shadow_dvo; unsigned int shadow_gpioe; unsigned int shadow_ddr; + unsigned int shadow_iinten;
Re: Does gpio_to_irq() work for MPC52xx gpios?
Peter Korsgaard wrote: >>>>>> "Bill" == Bill Gatliff writes: >>>>>> > > Bill> Guys: > Bill> Is it possible to specify an individual GPIO pin as an interrupt source > Bill> with the current MPC52xx code? > > No (not yet). In Ben's latest pull request there's a patch from me to > add basic infrastructure for gpio_to_irq(). I've recently added irq > support to the mpc8xxx driver, but so far nothing has been written for > 52xx. > > http://patchwork.ozlabs.org/patch/41550/ > Ok, after looking at your code for a few days I'm even more lost than when I started! On the MPC5200, all the GPIO_WKUP pins are multiplexed into a single interrupt line, which is Main_Mask8. As currently defined by mpc52xx_pic.c, that's a virtual interrupt number of 72. So generally speaking, if I do a request_irq() on 72, I'll get an interrupt any time an enabled GPIO_WKUP pin changes state. What I want to be able to do is a request_irq(gpio_to_irq(GPIO_WKUP_7), ...), so that I can have a single interrupt handler for each GPIO_WKUP pin. To do this, I think the general idea is as follows: 1. create a virtual interrupt number for each GPIO_WKUP line 2. install a chained interrupt handler on interrupt 72 3. inside the chained handler, map each active GPIO_WKUP pin to its associated virtual interrupt number, and invoke the associated interrupt handler by passing that virtual interrupt number to generic_handle_irq() 4. provide a gpio_to_irq that can map GPIO offsets to their associated virtual interrupt numbers I'm trying to implement the above, but I'm getting lost in all the IRQ mapping and virtualization. Can someone show me what I'm doing wrong in my code? I've put a complete copy of my modified mpc52xx_gpio.c on pastebin, with my portions highlighted: http://pastebin.com/f4c074ab8 A kernel message buffer log is here, also with the interesting lines highlighted: http://pastebin.com/f378d3c61 I get a mapping from hwirq 72 to a virq of 16. That seems fine. But that's the extent of the good news. :) The two GPIO pins I'm interested in are 222 and 223, which are GPIO_WKUP_6 and GPIO_WKUP_7. In my gpio_to_irq() I'm doing this: static int mpc52xx_wkup_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); struct mpc52xx_gpiochip *c = to_mpc52xx_gpiochip(mm); pr_err("%s mapping offset %d\n", __func__, offset); if (c->irqhost && offset < MPC52XX_WKUP_GPIO_PINS) return irq_create_mapping(c->irqhost, c->irq); return -ENXIO; } That's not giving me what I want, it's just creating another mapping to virtual irq 16. I know that code is wrong, I just don't know what the right code should be... Help, I'm lost! :) Kindest regards, b.g. -- Bill Gatliff Embedded systems training and consulting http://billgatliff.com b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Does gpio_to_irq() work for MPC52xx gpios?
Bill Gatliff wrote: > Guys: > > > Ok, I have gpio_to_irq() more-or-less showing signs of life for the > MPC5200. But I'm having some trouble using it the way I want to. > I think I've got the idea all of a sudden. In order to describe the inputs to my rotary encoder using the syntax I want, I have to implement something similar to of_get_gpio_flags(), right? b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Does gpio_to_irq() work for MPC52xx gpios?
Guys: Ok, I have gpio_to_irq() more-or-less showing signs of life for the MPC5200. But I'm having some trouble using it the way I want to. Recall that I have a rotary encoder that's tied to IRQ2 and GPIO_WKUP_7. I want to be able to describe it something like this: rotary-encoder { compatible = "linux,rotary-encoder","rotary-encoder"; interrupts = <&mpc5200_pic 2 3 &gpio_wkup 0 1>; // "IRQ2 on the MPC5200 PIC, // and pin 0 on GPIO_WKUP" type = <1>; // what event signal to generate val-ccw = <0x4a>; // what code to use for counter-clockwise rotation val-cw = <78>; // what code to use for clockwise rotation }; I've had some limited success with this, but not for any good reason. It turns out that the explanation for why I was getting a valid number for the first interrupt specification was because the device tree compiler was assuming that the interrupt-parent was the mpc5200_pic; my reference to the node in that list was utterly meaningless. The dtc also appears to have ignored the &gpio_wkup word, and interpreted the following zero as being the zero-th interrupt channel in the mpc5200_pic. Or something like that. Clearly, I don't understand the device tree syntax at all yet. Anyway, when I change the statement to this: rotary-encoder { compatible = "linux,rotary-encoder","rotary-encoder"; interrupt-parent = <&gpio_wkup>; interrupts = <0 0>; type = <1>; val-ccw = <0x4a>; val-cw = <78>; }; ... then the magic number that the dtc comes up with is causing my new chained interrupt handler for the gpio_wkup peripheral to come alive. (Of course it doesn't actually work yet, but that's not the point!) So here's my question: does the device tree compiler/syntax limit you to only one interrupt parent? I think the answer is no, because what I'm trying to do doesn't seem that much different from how one specifies GPIO pins coming from different controllers. Any suggestions? b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Does gpio_to_irq() work for MPC52xx gpios?
Bill Gatliff wrote: > Peter Korsgaard wrote: > >> No (not yet). In Ben's latest pull request there's a patch from me to >> add basic infrastructure for gpio_to_irq(). I've recently added irq >> support to the mpc8xxx driver, but so far nothing has been written for >> 52xx. >> >> http://patchwork.ozlabs.org/patch/41550/ >> >> > > Ok. I'm taking a look at that code now, planning to adapt it for the > MPC52xx unless someone raises any objections. > Ok, working on this now. I'm pretty far along, but I'm stopped at what I think is a device tree source file problem. I have an external device that generates two interrupt outputs. One of them is connected to IRQ2, the other to GPIO_WKUP_7. I'm describing the device like this: ... soc5...@f000 { #address-cells = <1>; #size-cells = <1>; compatible = "fsl,mpc5200b-immr","simple-bus"; ranges = <0 0xf000 0xc000>; reg = <0xf000 0x0100>; bus-frequency = <0>;// from bootloader system-frequency = <0>;// from bootloader ... mpc5200_pic: interrupt-control...@500 { // 5200 interrupts are encoded into two levels; interrupt-controller; gpio-controller; #interrupt-cells = <3>; #address-cells = <0>; #size-cells = <0>; compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic"; reg = <0x500 0x80>; interrupts = < 0 0 3 1 1 3 2 2 2 3 3 2 >; }; gpio_wkup: g...@c00 { compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup"; #gpio-cells = <2>; #interrupt-cells = <2>; #address-cells = <0>; #size-cells = <0>; reg = <0xc00 0x40>; interrupts = <1 8 0 0 3 0>; interrupt-parent = <&mpc5200_pic>; gpio-controller; interrupt-controller; }; ... }; ... system { compatible = "simple-bus"; rotary-encoder { compatible = "linux,rotary-encoder","rotary-encoder"; interrupts = <&mpc5200_pic 2 3 &gpio_wkup 0 0>; //interrupts = <&mpc5200_pic 2 3>; //gpios = <&gpio_wkup 0 0>; type = <1>; val-ccw = <0x4a>; val-cw = <78>; }; }; When I use the "gpios" property instead of the above, I get a useful gpio number and I can see the signal using sys/class/gpio. And I also know the hardware is working because an ancient, pre-device-tree kernel is working fine. :) The problem is that I'm not getting a valid number out for the second interrupt specification, presumably because the dts compiler doesn't have any idea how to generate the data--- and I have no idea how to fix that. I captured some dmesg information which shows the problem. The first line is for IRQ2, which is correct. The second is for GPIO_WKUP_7, which the kernel chokes on: ... irq: irq_create_mapping(0xcf814000, 0x42) irq: -> using host @cf814000 alloc irq_desc for 66 on node 0 alloc kstat_irqs on node 0 mpc52xx_irqhost_map: External IRQ2 virq=42, hw=42. type=8 irq: irq 66 on host /soc5...@f000/interrupt-control...@500 mapped to virtual irq 66 mpc52xx_extirq_set_type: irq=42. l2=2 flow_type=8 linux,rotary-encoder rotary-encoder.3: irq[0] 66 gpio[0] -2 <- my driver's output, the "magic number" was 66 return 0, l1=4, l2=0 irq: irq_create_mapping(0xcf814000, 0x0) irq: -> using host @cf814000 alloc irq_desc for 16 on node 0 alloc kstat_irqs on node 0 mpc52xx_irqhost_map: External IRQ0 virq=10, hw=0. type=8 irq: irq 0 on host /soc5...@f000/interrupt-control...@500 mapped to virtual irq 16 mpc52xx_extirq_set_type: irq=0. l2=0 flow_type=8 linux,rotary-encoder rotary-encoder.3: irq[1] 16 gpio[1] -2 <- my
Re: Does gpio_to_irq() work for MPC52xx gpios?
Peter Korsgaard wrote: > > No (not yet). In Ben's latest pull request there's a patch from me to > add basic infrastructure for gpio_to_irq(). I've recently added irq > support to the mpc8xxx driver, but so far nothing has been written for > 52xx. > > http://patchwork.ozlabs.org/patch/41550/ > Ok. I'm taking a look at that code now, planning to adapt it for the MPC52xx unless someone raises any objections. b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Does gpio_to_irq() work for MPC52xx gpios?
Guys: Is it possible to specify an individual GPIO pin as an interrupt source with the current MPC52xx code? I don't see anything in mpc52xx_gpio.c that registers an interrupt handler, which I think would be a necessary step towards demultiplexing the GPIO interrupt event. So I'm thinking that code to allow me to register an interrupt handler for a specific GPIO pin just isn't there... b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Question on MPC52xx IRQ[123] pins
Guys: I think I already know the answer to this, having read most of the MPC52xx manual. But I'll ask anyway, just to be sure I'm not missing something obvious... :) Is it possible to treat the external IRQ[123] pins on the MPC52xx as GPIO inputs? And if so, how do I tweak my dts file and other code, if necessary, to make that happen? Reason I ask is, I'm trying to enhance drivers/input/misc/rotary-encoder.c to use device trees, and one of the encoder inputs is on IRQ2. My strategy so far is to just provide an of_probe() function that builds a rotary_encoder_platform_data structure and then calls platform_device_register(). And that ain't working. :) First off, the rotary-encoder driver assumes that both of its inputs are both known to gpiolib, so that they can do both gpio_to_irq() and gpio_get_value() on them. There isn't any existing code that I can find that allows you to read the states of IRQ pins, be it under gpiolib or otherwise. And I think the reason for that is that there's no way to actually read the states of those pins at all--- the hardware just doesn't work that way. Or am I missing something? Second, if I get all this working then my rotary encoders won't be platform devices--- they'll be openfirmware devices, which means I'll have to do other work in the code as well. That's a subtle point I know, but rotary-encoder's assumption that all rotary encoder devices are also platform devices is kind of like mixing policy with implementation, it turns out. Almost like trying to reuse a PCI driver as a platform driver. I didn't spot how important that was until I started hacking on the code itself... Thanks! b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Trouble specifying dts gpio-leds with GPIO expander chip
Guys: I'm trying to come up with the right stuff for my dts file to assign a Linux "heartbeat" trigger to an I2C GPIO expansion device (MAX7314). I'm running on a platform that is very similar to the lite5200b, with linux-2.6.32. I'm a bit new to the device tree concept, having come most recently from an ARM world, so please be gentle... :) I have this so far: soc5...@f000 { #address-cells = <1>; #size-cells = <1>; compatible = "fsl,mpc5200b-immr","simple-bus"; ranges = <0 0xf000 0xc000>; reg = <0xf000 0x0100>; bus-frequency = <0>;// from bootloader system-frequency = <0>;// from bootloader ... i...@3d40 { #address-cells = <1>; #size-cells = <0>; compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c"; reg = <0x3d40 0x40>; interrupts = <2 16 0>; lext20: max7...@20 { #gpio-cells = <2>; compatible = "maxim,max7314","phillips,pca953x"; reg = <0x20>; linux,phandle = <0x20>; gpio-controller; }; ... }; }; ... system { compatible = "simple-bus"; gpio-leds { compatible = "gpio-leds"; heartbeat { gpios = <&lext20 3 0>; linux,default-trigger = "heartbeat"; }; }; }; ... The MAX7314 chip is showing up under /debug/gpio: # cat /debug/gpio ... GPIOs 198-213, i2c/1-0020, max7314, can sleep: And, indeed, I can twiddle the LED by hand: # echo 201 > /sys/class/gpio/export # while true; do for led in high low; \ do echo $led > /sys/class/gpio/gpio201/direction; \ sleep 1; done; done (observe blinking) But I see this at boot: Skipping unavailable LED gpio -19 (heartbeat) That error code is -ENODEV. I double-checked that gpio-leds is showing up on of_platform: # ls /sys/bus/of_platform/devices/ ... gpio-leds.2 ... I'm stumped. Could it be that the startup code is trying to register the heartbeat device before it has registered the MAX7314, so it doesn't know yet that the GPIO line exists? Anyone have any suggestions? b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Accessing flash directly from User Space
Jonathan Haws wrote: >>> How can I get that pointer? Unfortunately I cannot simply use the >>> >> address of the flash. Is there some magical function call that >> gives me access to that portion of the memory space? >> >> $ man 2 mmap >> >> You want MAP_SHARED and O_SYNC. >> > > > To use that I need to have a file descriptor to a device, do I not? However, > I do not have a base flash driver to give me that file descriptor. Am I > missing something with that call? > /dev/mem b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: Accessing flash directly from User Space
Jonathan Haws wrote: > > How can I get that pointer? Unfortunately I cannot simply use the address of > the flash. Is there some magical function call that gives me access to that > portion of the memory space? > $ man 2 mmap You want MAP_SHARED and O_SYNC. b.g. -- Bill Gatliff b...@billgatliff.com ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH/RFC] Add Alternative Log Buffer Support for printk Messages
Matt Sealey wrote: > Yes, there's FirmWorks, CodeGen SmartFirmware, IBM SLOF and OpenBIOS.. > they're all linked from the OpenBIOS website (along with a bunch of the > documentation from http://www.openfirmware.org in more-readable formats > like PDF) > > http://www.openbios.org/ > > > But here's the real question; why do you need an opensource > implementation? Curiosity? That, and I prefer Free *ware whenever that's an option. :) Nothing against the commercial alternatives, of course. But I'm already doing my own heavy lifting, because my platforms are all full-custom with very limited production runs. Since I'm into the guts of all my code anyway, I'm not inclined to outsource a bootloader development effort. Just trying to figure out where the walls of this "sandbox" are. I've been aware of the concept of Open Firmware for a while, but haven't really looked into it before now--- mostly because my impression until now was that the available implementations were both closed-source, and not supporting embedded, non-PPC targets like ARM. b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [PATCH/RFC] Add Alternative Log Buffer Support for printk Messages
Matt Sealey wrote: > I can think of a bunch of reasons why it's a good idea.. Can you point to a GPL/LGPL/BSD/etc. source code for an OpenFirmware implementation? b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Proposal for a Generic PWM Device API posted on linux-embedded
Greetings, all! I just posted code to implement a Generic PWM Device API to linux-embedded. If you need them, archives of that mailing list are available at the following link (and elsewhere): http://www.mail-archive.com/[EMAIL PROTECTED]/ Previous versions of this code were posted on linux-arm-kernel, linuxppc-dev, avr32linux.org and elsewhere. It's an API that cuts across machine architectures--- not unlike the GPIO API--- and I really appreciate the constructive feedback I have received from all corners of the architecture globe. Multiple reviewers suggested that the best place to review the final code is linux-embedded, rather than cross-posting all over the place. I encourage you to submit your feedback there. I would love to see this code included in the mainline kernel at some point in the not-too-distant future. It has proven very useful to me, I think it will be useful for many others as well. Kindest regards, b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: Floating inputs on unused GPIO pins
Laurent Pinchart wrote: > > There are no internal pull-up or pull-down resistors on the MPC8248 GPIO > pins. I know our hardware engineer has a valid point theoretically. Does the > point stand practically, or does the MPC8248 > "state-of-the-art"(tm)(c)(whatever) technology make floating inputs safe ? Well, Freescale's own layout recommendations recommend pullups or pulldowns for all input pins, but it's isn't clear what motivates that suggestion. The block diagram, Figure 37-21, is less than helpful. :) I recall a doc somewhere that showed the input protection circuitry ends up providing a modest pullup/down, so the line never truly "floats". But it's a very high-impedance path, and I can't seem to find the doc anyway so it could be for a completely different chip altogether. The part isn't going to blow up if you leave inputs unconnected, at least if you avoid high-EMI/RFI environments. But I can imagine the possibility of increased power consumption if I try hard enough. I would think that the magnitude would be completely swamped by the consumption of the rest of the chip, however... The technical answer might not be the best political one, at least not without Freescale-branded docs to back you up. I say, write the code and make everyone else happy. :) At least until someone plugs in that expansion module! b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Paul Mundt wrote: >> Hasn't been a problem so far. I posted the first version of the code on >> l-a-k, >> and got some feedback on the pwm_device API and a lot of feedback on the way >> users wanted to use the API to realize applications. I incorporated all of >> it, >> and in this "release" I broadened the exposure per recommendations received >> from >> l-a-k. >> > This is precisely the problem. Stuff that gets "reviewed" on > linux-arm-kernel gets reviewed for ARM only. There has been way too much > crap that has been pushed into the kernel under the guise of being > generic and "reviewed" that has broken _every_ architecture _except_ ARM. > If you want to refute this, go look at the recent fiasco with musb, which > still hasn't been solved properly, primarily because the ARM people > couldn't be bothered using grep. This crap happens all the time, because > stuff is reviewed and merged in private, and the only time anyone else > notices is when their platform suddenly stops building. I'll note for the record that I didn't post on linux-arm-kernel only. Otherwise, we wouldn't be having this discussion. :) > Your first version should have been to linux-embedded and linux-kernel. > If you want to alert the linux-arm-kernel people to the fact that a > discussion is going on in this area, then feel free to post a > notification to the list with references to the relevant lists. There is > no reason why public lists should have to dig in to private archives to > try and play catch up. I'm not asking anyone to do that. Just review the patches posted to the list of your choice. Or, don't review them. Up to you. My next update will be the one where I formally request a review with intent to merge into mainline. That one will go to linux-embedded only, with notifications sent elsewhere as indicated per community request. I don't have a problem with that. I can't change history, but I'm doing what you are asking of me otherwise. > If you're trying to pitch a generic API and doing your review on a > private list, you've already lost. If you're talking about things that > only effect arch/arm, feel free to do whatever you want. As soon as you > step outside of that structure, you have to follow common convention, or > you risk breaking things all over the place. I can't remember the last > time I saw a "generic" API reviewed on linux-arm-kernel that didn't end > up breaking every other architecture in existence. This is true for > drivers, also. Better yet, don't bother dropping the ARM depedency until > you've posted to a public list. Again, we wouldn't be having this exchange if I was pitching a generic API on a private list because I sense that you aren't an l-a-k subscriber. :) It's true that the early posts were on the ARM list, but you can see that I didn't stop there. I started there because the platform that supports the API right now is ARM, and so I wanted that part to be right before moving upstream. That process worked: I received feedback on the ARM-specific bits which improved the API as a whole. The diversity of ARM machines plus Blackfin, PPC, MIPS, X, Y, Z and PDQ machines was more than I could deal with until now. Right, enough of that. I really don't want to get distracted from the code. I'll readily admit to not handing the mailing list submissions right, and I resolve to do a better job effective immediately. But I think that's the last that I need to say on the subject. If it makes you feel any better, I'll stop responding to your replies unless they come to me via linux-embedded. :) > Some of us are pretty damn tired of cleaning up after the ARM people. Sounds like the ARM people need you to drop by and help them do a better job. Sounds like you could directly benefit from their doing a better job, too. Win-win. b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Paul Mundt wrote: > On Fri, Oct 10, 2008 at 09:03:34AM -0500, Bill Gatliff wrote: >> Paul Mundt wrote: >>> This is likely because some of those lists are subscribers only, so cross >>> posting is poor form. It makes sense to keep the discussion in one place, >>> and to send notification messages with a pointer to the list archives to >>> the other lists so folks can jump in if they really care. Splitting it >>> out doesn't help matters in the least, but unfortunately this is what >>> seems to happen the most when subscribers only lists are involved. >> Alright, then maybe I can do this when I post the "final" changeset for >> review: >> cross-post to lkml and linux-embedded, and then post one short note on l-a-k, >> linuxppc-dev and elsewhere that refers those interested to the actual >> content. >> I can live with that. >> > linux-arm-kernel is the only one that is subscribers only out of that > list, according to MAINTAINERS. If rmk wants to mandate a broken policy, > that's perfectly fine, just don't expect the rest of the kernel community > to tolerate it. Problem is, the rest of the kernel community is the one who takes it in the, ahem, server when I cross-post. And since my reference platform is currently ARM, I can't leave l-a-k out. b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 1/6] [PWM] Generic PWM API implementation
Benjamin Herrenschmidt wrote: > On Wed, 2008-10-08 at 11:43 -0500, Bill Gatliff wrote: >> Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> >> --- > > And you haven't provided -any- changeset comment. That isn't good :-) What's the easiest way to do that with git? I'm using git-format-patch and git-send-email to produce the changeset emails themselves, after extensive use of git-add --interactive and git-rebase --interactive to get rid of the "mundane" commit stuff that I do because of my highly interrupt-driven workflow. Should I just edit the files that come out of git-format-patch? b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Jon Smirl wrote: > What do the device tree deities have to say about PWM support? Dunno. What lists are they on? :) b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Paul Mundt wrote: > This is likely because some of those lists are subscribers only, so cross > posting is poor form. It makes sense to keep the discussion in one place, > and to send notification messages with a pointer to the list archives to > the other lists so folks can jump in if they really care. Splitting it > out doesn't help matters in the least, but unfortunately this is what > seems to happen the most when subscribers only lists are involved. Alright, then maybe I can do this when I post the "final" changeset for review: cross-post to lkml and linux-embedded, and then post one short note on l-a-k, linuxppc-dev and elsewhere that refers those interested to the actual content. I can live with that. b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
David Woodhouse wrote: > Subscriber-only lists are broken. Just don't use them. You owe me a new keyboard! :) b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Geert Uytterhoeven wrote: > > Were did you actually sent them to? Apparently you sent them to each mailing > list (at least linux-embedded and linuxppc-dev) _separately_ (or using bcc). I sent them separately to linux-embedded, linuxppc-dev, and linux-arm-kernel. Those three groups seemed to have the developers who were most likely to provide a motivated review and constructive response; unfortunately, some are subscriber-only and so I couldn't just cross-post. I was expecting some criticism for this, but I'm not sure there's a good alternative. I don't like the idea of posting in so many places, but PWM is a pretty expansive topic: just about every SoC under the sun has some ability to do PWM, and people use the signals for all sorts of things. Both have to be taken into consideration by the API, hence I need lots of review and feedback. There isn't a lot of traffic on linux-embedded, and I'm not sure how many people who read linux-arm-kernel also read linuxppc-dev. Lkml's topic coverage is huge, so I don't know how many hardcore embedded developers I would encounter there. I was hoping for a round of feedback at a lower level before pushing anything upstream like that. > Hence different people may give the same comments without knowing about each > other, and you may have to explain everything multiple times. Hasn't been a problem so far. I posted the first version of the code on l-a-k, and got some feedback on the pwm_device API and a lot of feedback on the way users wanted to use the API to realize applications. I incorporated all of it, and in this "release" I broadened the exposure per recommendations received from l-a-k. > I would go for lkml and linux-embedded, _together_. So, you're saying the same thing as me, basically. But leaving out the lists with very high ratios of device-specific domain knowledge, which is important for the backend parts of what I'm proposing. Blackfin's PWM-capable peripherals work differently from those commonly found in ARM and PPC, for example. I haven't run anything by the MIPS or AVR guys, but I'm guessing they would have something to add, too. I'm beginning to appreciate what everyone must have had to deal with for GPIO. :) b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 1/6] [PWM] Generic PWM API implementation
Benjamin Herrenschmidt wrote: > On Wed, 2008-10-08 at 11:43 -0500, Bill Gatliff wrote: >> Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> >> --- > > And you haven't provided -any- changeset comment. That isn't good :-) Apparently not. :) b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Benjamin Herrenschmidt wrote: > On Wed, 2008-10-08 at 11:43 -0500, Bill Gatliff wrote: >> This series proposes a "generic PWM" driver API. >> >> This proposed API is motivated by the author's need to support >> pluggable devices; a secondary objective is to consolidate the >> existing PWM implementations behind an agreeable, consistent, >> redundancy-reducing interface. > > .../... > > You should send your patches to the main linux kernel list ! Perhaps. But it seemed more relevant to this crowd, and the linux-embedded crowd, and the linux-arm-kernel crowd. At the very least, it made sense to present it in this sort of venue first. Given that it's a "global" API proposal, I suppose I'll have to run it by lkml at some point--- unless one of the aforementioned groups can mainline it themselves. b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [RFC 0/6] Proposal for a Generic PWM Device API
Matt Sealey wrote: > I'm all for this if you manage it. > > The code and API looks good. We have some projects which involve PWM > and having a nice clean standard API like the GPIO API was on the > wishlist.. this will make it so much easier to do fan control, > backlight control, drive motors, audio output, and the billion > other things.. /me blushes Aw, shucks. I'm just glad I could help. :) b.g. -- Bill Gatliff [EMAIL PROTECTED] ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev
[RFC 4/6] [PWM] Driver for Atmel PWMC peripheral
Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> --- drivers/pwm/atmel-pwm.c | 631 +++ 1 files changed, 631 insertions(+), 0 deletions(-) create mode 100644 drivers/pwm/atmel-pwm.c diff --git a/drivers/pwm/atmel-pwm.c b/drivers/pwm/atmel-pwm.c new file mode 100644 index 000..b65e84f --- /dev/null +++ b/drivers/pwm/atmel-pwm.c @@ -0,0 +1,631 @@ +/* + * drivers/pwm/atmel-pwm.c + * + * Copyright (C) 2008 Bill Gatliff + * Copyright (C) 2007 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +enum { + /* registers common to the PWMC peripheral */ + PWMC_MR = 0, + PWMC_ENA = 4, + PWMC_DIS = 8, + PWMC_SR = 0xc, + PWMC_IER = 0x10, + PWMC_IDR = 0x14, + PWMC_IMR = 0x18, + PWMC_ISR = 0x1c, + + /* registers per each PWMC channel */ + PWMC_CMR = 0, + PWMC_CDTY = 4, + PWMC_CPRD = 8, + PWMC_CCNT = 0xc, + PWMC_CUPD = 0x10, + + /* how to find each channel */ + PWMC_CHAN_BASE = 0x200, + PWMC_CHAN_STRIDE = 0x20, + + /* CMR bits of interest */ + PWMC_CMR_CPD = 10, + PWMC_CMR_CPOL = 9, + PWMC_CMR_CALG = 8, + PWMC_CMR_CPRE_MASK = 0xf, +}; + +struct atmel_pwm { + struct pwm_device pwm; + spinlock_t lock; + void __iomem *iobase; + struct clk *clk; + u32 *sync_mask; + int irq; + u32 ccnt_mask; +}; + + +static inline void +pwmc_writel(const struct atmel_pwm *p, + unsigned offset, u32 val) +{ + __raw_writel(val, p->iobase + offset); +} + + +static inline u32 +pwmc_readl(const struct atmel_pwm *p, + unsigned offset) +{ + return __raw_readl(p->iobase + offset); +} + + +static inline void +pwmc_chan_writel(const struct pwm_channel *p, +u32 offset, u32 val) +{ + const struct atmel_pwm *ap + = container_of(p->pwm, struct atmel_pwm, pwm); + + if (PWMC_CMR == offset) + val &= ((1 << PWMC_CMR_CPD) + | (1 << PWMC_CMR_CPOL) + | (1 << PWMC_CMR_CALG) + | (PWMC_CMR_CPRE_MASK)); + else + val &= ap->ccnt_mask; + + pwmc_writel(ap, offset + PWMC_CHAN_BASE + + (p->chan * PWMC_CHAN_STRIDE), val); +} + + +static inline u32 +pwmc_chan_readl(const struct pwm_channel *p, + u32 offset) +{ + const struct atmel_pwm *ap + = container_of(p->pwm, struct atmel_pwm, pwm); + + return pwmc_readl(ap, offset + PWMC_CHAN_BASE + + (p->chan * PWMC_CHAN_STRIDE)); +} + + +static inline int +__atmel_pwm_is_on(struct pwm_channel *p) +{ + struct atmel_pwm *ap = container_of(p->pwm, struct atmel_pwm, pwm); + return (pwmc_readl(ap, PWMC_SR) & (1 << p->chan)) ? 1 : 0; +} + + +static inline void +__atmel_pwm_unsynchronize(struct pwm_channel *p, + struct pwm_channel *to_p) +{ + const struct atmel_pwm *ap + = container_of(p->pwm, struct atmel_pwm, pwm); + int wchan; + + if (to_p) { + ap->sync_mask[p->chan] &= ~(1 << to_p->chan); + ap->sync_mask[to_p->chan] &= ~(1 << p->chan); + goto done; + } + + ap->sync_mask[p->chan] = 0; + for (wchan = 0; wchan < ap->pwm.nchan; wchan++) + ap->sync_mask[wchan] &= ~(1 << p->chan); +done: + pr_debug("%s:%d sync_mask %x\n", +p->pwm->bus_id, p->chan, ap->sync_mask[p->chan]); +} + + +static inline void +__atmel_pwm_synchronize(struct pwm_channel *p, + struct pwm_channel *to_p) +{ + const struct atmel_pwm *ap + = container_of(p->pwm, struct atmel_pwm, pwm); + + if (!to_p) + return; + + ap->sync_mask[p->chan] |= (1 << to_p->chan); + ap->sync_mask[to_p->chan] |= (1 << p->chan); + + pr_debug("%s:%d sync_mask %x\n", +p->pwm->bu
[RFC 1/6] [PWM] Generic PWM API implementation
Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> --- drivers/pwm/pwm.c | 667 + 1 files changed, 667 insertions(+), 0 deletions(-) create mode 100644 drivers/pwm/pwm.c diff --git a/drivers/pwm/pwm.c b/drivers/pwm/pwm.c new file mode 100644 index 000..2f28c20 --- /dev/null +++ b/drivers/pwm/pwm.c @@ -0,0 +1,667 @@ +/* + * drivers/pwm/pwm.c + * + * Copyright (C) 2008 Bill Gatliff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int __pwm_create_sysfs(struct pwm_device *pwm); + +static LIST_HEAD(pwm_device_list); +static DEFINE_MUTEX(device_list_mutex); +static struct class pwm_class; +static struct workqueue_struct *pwm_handler_workqueue; + + +int pwm_register(struct pwm_device *pwm) +{ + struct pwm_channel *p; + int wchan; + int ret = 0; + + spin_lock_init(&pwm->list_lock); + + p = kcalloc(pwm->nchan, sizeof(struct pwm_channel), GFP_KERNEL); + if (!p) + return -ENOMEM; + + for (wchan = 0; wchan < pwm->nchan; wchan++) { + spin_lock_init(&p[wchan].lock); + init_completion(&p[wchan].complete); + p[wchan].chan = wchan; + p[wchan].pwm = pwm; + } + + pwm->channels = p; + + mutex_lock(&device_list_mutex); + + list_add_tail(&pwm->list, &pwm_device_list); + ret = __pwm_create_sysfs(pwm); + if (ret) { + mutex_unlock(&device_list_mutex); + goto err_create_sysfs; + } + + mutex_unlock(&device_list_mutex); + + pr_info("%s: %d channels\n", pwm->bus_id, pwm->nchan); + return 0; + +err_create_sysfs: + kfree(p); + + return ret; +} +EXPORT_SYMBOL(pwm_register); + + +static int __match_device(struct device *dev, void *data) +{ + return dev_get_drvdata(dev) == data; +} + + +int pwm_unregister(struct pwm_device *pwm) +{ + int wchan; + struct device *dev; + + mutex_lock(&device_list_mutex); + + for (wchan = 0; wchan < pwm->nchan; wchan++) { + if (pwm->channels[wchan].flags & FLAG_REQUESTED) { + mutex_unlock(&device_list_mutex); + return -EBUSY; + } + } + + for (wchan = 0; wchan < pwm->nchan; wchan++) { + dev = class_find_device(&pwm_class, NULL, + &pwm->channels[wchan], + __match_device); + if (dev) { + put_device(dev); + device_unregister(dev); + } + } + + kfree(pwm->channels); + list_del(&pwm->list); + mutex_unlock(&device_list_mutex); + + return 0; +} +EXPORT_SYMBOL(pwm_unregister); + + +static struct pwm_device * +__pwm_find_device(const char *bus_id) +{ + struct pwm_device *p; + + list_for_each_entry(p, &pwm_device_list, list) + { + if (!strcmp(bus_id, p->bus_id)) + return p; + } + return NULL; +} + + +static int +__pwm_request_channel(struct pwm_channel *p, + const char *requester) +{ + int ret; + + if (test_and_set_bit(FLAG_REQUESTED, &p->flags)) + return -EBUSY; + + if (p->pwm->request) { + ret = p->pwm->request(p); + if (ret) { + clear_bit(FLAG_REQUESTED, &p->flags); + return ret; + } + } + + p->requester = requester; + return 0; +} + + +struct pwm_channel * +pwm_request(const char *bus_id, + int chan, + const char *requester) +{ + struct pwm_device *p; + int ret; + + mutex_lock(&device_list_mutex); + + p = __pwm_find_device(bus_id); + if (!p || chan >= p->nchan) + goto err_no_device; + + if (!try_module_get(p->owner)) + goto err_module_get_failed; + + ret = __pwm_request_channel(&p->cha
[RFC 5/6] [PWM] Install new Atmel PWMC driver in Kconfig, expunge old one
Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> --- arch/arm/Kconfig |2 + drivers/Makefile |2 + drivers/misc/Kconfig |9 - drivers/misc/Makefile|1 - drivers/misc/atmel_pwm.c | 409 -- drivers/pwm/Kconfig | 24 +++ drivers/pwm/Makefile |6 + 7 files changed, 34 insertions(+), 419 deletions(-) delete mode 100644 drivers/misc/atmel_pwm.c create mode 100644 drivers/pwm/Kconfig create mode 100644 drivers/pwm/Makefile diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 70dba16..fed3eef 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1196,6 +1196,8 @@ source "drivers/spi/Kconfig" source "drivers/gpio/Kconfig" +source "drivers/pwm/Kconfig" + source "drivers/w1/Kconfig" source "drivers/power/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 2735bde..f242fc6 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -6,6 +6,8 @@ # obj-y += gpio/ +obj-$(CONFIG_GENERIC_PWM) += pwm/ + obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_RAPIDIO) += rapidio/ diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a726f3b..cdea0bb 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -13,15 +13,6 @@ menuconfig MISC_DEVICES if MISC_DEVICES -config ATMEL_PWM - tristate "Atmel AT32/AT91 PWM support" - depends on AVR32 || ARCH_AT91 - help - This option enables device driver support for the PWM channels - on certain Atmel prcoessors. Pulse Width Modulation is used for - purposes including software controlled power-efficent backlights - on LCD displays, motor control, and waveform generation. - config ATMEL_TCLIB bool "Atmel AT32/AT91 Timer/Counter Library" depends on (AVR32 || ARCH_AT91) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c6c13f6..9e67012 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_EEEPC_LAPTOP)+= eeepc-laptop.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_COMPAL_LAPTOP)+= compal-laptop.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o -obj-$(CONFIG_ATMEL_PWM)+= atmel_pwm.o obj-$(CONFIG_ATMEL_SSC)+= atmel-ssc.o obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o obj-$(CONFIG_HP_WMI) += hp-wmi.o diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c deleted file mode 100644 index 6aa5294..000 --- a/drivers/misc/atmel_pwm.c +++ /dev/null @@ -1,409 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - - -/* - * This is a simple driver for the PWM controller found in various newer - * Atmel SOCs, including the AVR32 series and the AT91sam9263. - * - * Chips with current Linux ports have only 4 PWM channels, out of max 32. - * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux). - * Docs are inconsistent about the width of the channel counter registers; - * it's at least 16 bits, but several places say 20 bits. - */ -#definePWM_NCHAN 4 /* max 32 */ - -struct pwm { - spinlock_t lock; - struct platform_device *pdev; - u32 mask; - int irq; - void __iomem*base; - struct clk *clk; - struct pwm_channel *channel[PWM_NCHAN]; - void(*handler[PWM_NCHAN])(struct pwm_channel *); -}; - - -/* global PWM controller registers */ -#define PWM_MR 0x00 -#define PWM_ENA0x04 -#define PWM_DIS0x08 -#define PWM_SR 0x0c -#define PWM_IER0x10 -#define PWM_IDR0x14 -#define PWM_IMR0x18 -#define PWM_ISR0x1c - -static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val) -{ - __raw_writel(val, p->base + offset); -} - -static inline u32 pwm_readl(const struct pwm *p, unsigned offset) -{ - return __raw_readl(p->base + offset); -} - -static inline void __iomem *pwmc_regs(const struct pwm *p, int index) -{ - return p->base + 0x200 + index * 0x20; -} - -static struct pwm *pwm; - -static void pwm_dumpregs(struct pwm_channel *ch, char *tag) -{ - struct device *dev = &pwm->pdev->dev; - - dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n", - tag, - pwm_readl(pwm, PWM_MR), - pwm_readl(pwm, PWM_SR), - pwm_readl(pwm, PWM_IMR)); - dev_dbg(dev, - "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n", - ch->index, - pwm_channel_readl(ch, PWM_CMR), - pwm_channel_readl(ch, PWM_CDTY), -
[RFC 2/6] [PWM] Changes to existing include/linux/pwm.h to adapt to generic PWM API
Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> --- include/linux/pwm.h | 168 -- 1 files changed, 147 insertions(+), 21 deletions(-) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 3945f80..d3d18f7 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -1,31 +1,157 @@ #ifndef __LINUX_PWM_H #define __LINUX_PWM_H -struct pwm_device; - /* - * pwm_request - request a PWM device + * include/linux/pwm.h + * + * Copyright (C) 2008 Bill Gatliff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -struct pwm_device *pwm_request(int pwm_id, const char *label); -/* - * pwm_free - free a PWM device - */ -void pwm_free(struct pwm_device *pwm); +enum { + PWM_CONFIG_DUTY_TICKS = BIT(0), + PWM_CONFIG_PERIOD_TICKS = BIT(1), + PWM_CONFIG_POLARITY = BIT(2), + PWM_CONFIG_START = BIT(3), + PWM_CONFIG_STOP = BIT(4), -/* - * pwm_config - change a PWM device configuration - */ -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns); + PWM_CONFIG_HANDLER = BIT(5), -/* - * pwm_enable - start a PWM output toggling - */ -int pwm_enable(struct pwm_device *pwm); + PWM_CONFIG_DUTY_NS = BIT(6), + PWM_CONFIG_DUTY_PERCENT = BIT(7), + PWM_CONFIG_PERIOD_NS = BIT(8), +}; + +struct pwm_channel; +struct work_struct; + +typedef int (*pwm_handler_t)(struct pwm_channel *p, void *data); +typedef void (*pwm_callback_t)(struct pwm_channel *p); + +struct pwm_channel_config { + int config_mask; + unsigned long duty_ticks; + unsigned long period_ticks; + int polarity; + + pwm_handler_t handler; + + unsigned long duty_ns; + unsigned long period_ns; + int duty_percent; +}; + +struct pwm_device { + struct list_head list; + spinlock_t list_lock; + struct device *dev; + struct module *owner; + struct pwm_channel *channels; + + const char *bus_id; + int nchan; + + int (*request) (struct pwm_channel *p); + void(*free) (struct pwm_channel *p); + int (*config) (struct pwm_channel *p, +struct pwm_channel_config *c); + int (*config_nosleep)(struct pwm_channel *p, + struct pwm_channel_config *c); + int (*synchronize) (struct pwm_channel *p, +struct pwm_channel *to_p); + int (*unsynchronize)(struct pwm_channel *p, +struct pwm_channel *from_p); + int (*set_callback) (struct pwm_channel *p, +pwm_callback_t callback); +}; + +int pwm_register(struct pwm_device *pwm); +int pwm_unregister(struct pwm_device *pwm); + +enum { + FLAG_REQUESTED = 0, + FLAG_STOP = 1, +}; + +struct pwm_channel { + struct list_head list; + struct pwm_device *pwm; + const char *requester; + int chan; + unsigned long flags; + unsigned long tick_hz; + + spinlock_t lock; + struct completion complete; + + pwm_callback_t callback; + + struct work_struct handler_work; + pwm_handler_t handler; + void *handler_data; + + int active_low; + unsigned long period_ticks; + unsigned long duty_ticks; +}; + +struct pwm_channel * +pwm_request(const char *bus_id, int chan, + const char *requester); + +void pwm_free(struct pwm_channel *pwm); + +int pwm_config_nosleep(struct pwm_channel *pwm, + struct pwm_channel_config *c); + +int pwm_config(struct pwm_channel *pwm, + struct pwm_channel_config *c); + +unsigned long pwm_ns_to_ticks(struct pwm_channel *pwm, + unsigned long nsecs); + +unsigned long pwm_ticks_to_ns(struct pwm_channel *pwm, + unsigned long ticks); + +int pwm_period_ns(struct pwm_channel *pwm, + unsigned long period_ns); + +int pwm_duty_ns(struct pwm_channel *pwm, + unsigned long duty_ns); + +int pwm_duty_percent(struct pwm_channel *pwm, +int percent); + +int pwm_polarity(struct pwm_channel *pwm, +int active_high); + +int pwm_start(struct pwm_channel *pwm); + +int pwm_stop(struct pwm_c
[RFC 3/6] [PWM] Documentation
Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> --- Documentation/pwm.txt | 258 + 1 files changed, 258 insertions(+), 0 deletions(-) create mode 100644 Documentation/pwm.txt diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt new file mode 100644 index 000..b8932dd --- /dev/null +++ b/Documentation/pwm.txt @@ -0,0 +1,258 @@ + Generic PWM Device API + + October 8, 2008 + Bill Gatliff + <[EMAIL PROTECTED]> + + + +The code in drivers/pwm and include/linux/pwm.h implements an API for +applications involving pulse-width-modulation signals. This document +describes how the API implementation facilitates both PWM-generating +devices, and users of those devices. + + + +Motivation + +The primary goals for implementing the "generic PWM API" are to +consolidate the various PWM implementations within a consistent and +redundancy-reducing framework, and to facilitate the use of +hotpluggable PWM devices. + +Previous PWM-related implementations within the Linux kernel achieved +their consistency via cut-and-paste, but did not need to (and didn't) +facilitate more than one PWM-generating device within the system--- +hotplug or otherwise. The Generic PWM Device API might be most +appropriately viewed as an update to those implementations, rather +than a complete rewrite. + + + +Challenges + +One of the difficulties in implementing a generic PWM framework is the +fact that pulse-width-modulation applications involve real-world +signals, which often must be carefully managed to prevent destruction +of hardware that is linked to those signals. A DC motor that +experiences a brief interruption in the PWM signal controlling it +might destructively overheat; it could change speed, losing +synchronization with a sensor; it could even suddenly change direction +or torque, breaking the mechanical device connected to it. + +(A generic PWM device framework is not directly responsible for +preventing the above scenarios: that responsibility lies with the +hardware designer and the application and driver authors. But it must +to the greatest extent possible make it easy to avoid such problems). + +A generic PWM device framework must accomodate the substantial +differences between available PWM-generating hardware devices, without +becoming sub-optimal for any of them. + +Finally, a generic PWM device framework must be relatively +lightweight, computationally speaking. Some PWM users demand +high-speed outputs, plus the ability to regulate those outputs +quickly. A device framework must be able to "keep up" with such +hardware, while still leaving time to do real work. + +The Generic PWM Device API is an attempt to meet all of the above +requirements. At its initial publication, the API was already in use +managing small DC motors through a custom-designed, optically-isolated +H-bridge driver. + + + +Functional Overview + +The Generic PWM Device API framework is implemented in +include/linux/pwm.h and drivers/pwm/pwm.c. The functions therein use +information from pwm_device, pwm_channel and pwm_channel_config +structures to invoke services in PWM peripheral device drivers. +Consult drivers/pwm/atmel-pwm.c for an example driver. + +There are two classes of adopters of the PWM framework: + + "Users" -- those wishing to employ the API merely to produce PWM + signals; once they have identified the appropriate physical output + on the platform in question, they don't care about the details of + the underlying hardware + + "Driver authors" -- those wishing to bind devices that can generate + PWM signals to the Generic PWM Device API, so that the services of + those devices become available to users; assuming the hardware can + support the needs of a user, driver authors don't care about the + details of the user's application + +Generally speaking, users will first invoke pwm_request() to obtain a +handle to a PWM device. They will then pass that handle to functions +like pwm_duty_ns() and pwm_period_ns() to set the duty cycle and +period of the PWM signal, respectively. They will also invoke +pwm_start() and pwm_stop() to turn the signal on and off. + +The framework also provides a sysfs interface to PWM devices, which is +adequate for basic needs and testing. + +Driver authors fill out a pwm_device structure, which describes the +capabilities of the PWM hardware being driven--- including the number +of distinct output "channels" the peripheral offers. They then invoke +pwm_register() (usually from within their device's probe() handler) to +make the PWM API aware of their device. The framework will call back +to the methods described in the pwm_device structure to configure and +use the hardware. + +Note that PWM signals can be produced by a variety of peripherals, +beyo
[RFC 6/6] [PWM] New LED driver and trigger that use PWM API
Signed-off-by: Bill Gatliff <[EMAIL PROTECTED]> --- drivers/leds/Kconfig | 21 -- drivers/leds/Makefile |2 + drivers/leds/leds-pwm.c| 141 drivers/leds/ledtrig-dim.c | 95 + include/linux/pwm-led.h| 34 +++ 5 files changed, 286 insertions(+), 7 deletions(-) create mode 100644 drivers/leds/leds-pwm.c create mode 100644 drivers/leds/ledtrig-dim.c create mode 100644 include/linux/pwm-led.h diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9556262..019c2e8 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -17,13 +17,6 @@ config LEDS_CLASS comment "LED drivers" -config LEDS_ATMEL_PWM - tristate "LED Support using Atmel PWM outputs" - depends on LEDS_CLASS && ATMEL_PWM - help - This option enables support for LEDs driven using outputs - of the dedicated PWM controller found on newer Atmel SOCs. - config LEDS_CORGI tristate "LED Support for the Sharp SL-C7x0 series" depends on LEDS_CLASS && PXA_SHARP_C7xx @@ -119,6 +112,12 @@ config LEDS_GPIO outputs. To be useful the particular board must have LEDs and they must be connected to the GPIO lines. +config LEDS_PWM + tristate "LED Support for PWM connected LEDs" + depends on LEDS_CLASS && GENERIC_PWM + help + Enables support for LEDs connected to PWM outputs. + config LEDS_CM_X270 tristate "LED Support for the CM-X270 LEDs" depends on LEDS_CLASS && MACH_ARMCORE @@ -190,6 +189,14 @@ config LEDS_TRIGGER_IDE_DISK This allows LEDs to be controlled by IDE disk activity. If unsure, say Y. +config LEDS_TRIGGER_DIM + tristate "LED Dimmer Trigger" + depends on LEDS_TRIGGERS + help + Regulates the brightness of an LED based on the 1-minute CPU + load average. Ideal for PWM-driven LEDs. + If unsure, say Y. + config LEDS_TRIGGER_HEARTBEAT tristate "LED Heartbeat Trigger" depends on LEDS_TRIGGERS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index ff7982b..1031086 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_LEDS_COBALT_QUBE)+= leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO)+= leds-gpio.o +obj-$(CONFIG_LEDS_PWM) += leds-pwm.o obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o @@ -27,5 +28,6 @@ obj-$(CONFIG_LEDS_PCA955X)+= leds-pca955x.o # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)+= ledtrig-ide-disk.o +obj-$(CONFIG_LEDS_TRIGGER_DIM) += ledtrig-dim.o obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c new file mode 100644 index 000..3bd9afb --- /dev/null +++ b/drivers/leds/leds-pwm.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include + + +struct led_pwm { + struct led_classdev led; + struct pwm_channel *pwm; + int percent; +}; + + +static void +led_pwm_brightness_set(struct led_classdev *c, + enum led_brightness b) +{ + struct led_pwm *led; + int percent; + + percent = (b * 100) / (LED_FULL - LED_OFF); + led = container_of(c, struct led_pwm, led); + led->percent = percent; + pwm_duty_percent(led->pwm, percent); +} + + +static enum led_brightness +led_pwm_brightness_get(struct led_classdev *c) +{ + struct led_pwm *led; + led = container_of(c, struct led_pwm, led); + return led->percent; +} + + +static int __init +led_pwm_probe(struct platform_device *pdev) +{ + struct pwm_led_platform_data *pdata = pdev->dev.platform_data; + struct led_pwm *led; + struct device *d = &pdev->dev; + int ret; + + if (!pdata || !pdata->led_info) + return -EINVAL; + + if (!try_module_get(d->driver->owner)) + return -ENODEV; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->pwm = pwm_request(pdata->bus_id, pdata->chan, + pdata->led_info->name); + if (!led->pwm) { + ret = -EINVAL; + goto err_pwm_request; + } + + platform_set_drvdata(pdev, led); + + led->led.name = pdat
[RFC 0/6] Proposal for a Generic PWM Device API
This series proposes a "generic PWM" driver API. This proposed API is motivated by the author's need to support pluggable devices; a secondary objective is to consolidate the existing PWM implementations behind an agreeable, consistent, redundancy-reducing interface. The code included in this patch draws heavily from the existing PWM infrastructure and driver for the AT91SAM9263 PWMC. The author is grateful to Russell King, Eric Miao, David Brownell and others for providing such tall "shoulders" to stand upon. The proposed updates to that code should not be interpreted as attempts to address shortcomings, but rather to extend functionality in ways that were not originally required. The implementation of the proposed API is structurally similar to the generic GPIO API, except that the PWM code uses platform bus_id strings instead of integers to identify devices. A configuration structure is also provided, so that the API can be extended in a source-code-compatible way to accomodate devices with features not anticipated by the current code. Pulse width modulated signals are used in an astounding number and range of applications, and there is no "one true way" of either realizing them or employing them to accomplish real work. The current proposal attempts to provide a useful feature set for the most basic users, packaged in such a way as to allow the API to be extended in a backwards-compatible way as new needs are identified. Some of these needs have already been identified. The proposed code has been run-tested on a Cogent CSB737 (AT91SAM9263), mated to a custom circuit that drives multiple DC motors and sensors. Feedback is welcome! b.g. -- Bill Gatliff <[EMAIL PROTECTED]> ========== Bill Gatliff (6): [PWM] Generic PWM API implementation [PWM] Changes to existing pwm.h to adapt to generic PWM API [PWM] Documentation [PWM] Driver for Atmel PWMC peripheral [PWM] Install new Atmel PWMC driver in Kconfig, expunge old one [PWM] New LED driver and trigger that use PWM API Documentation/pwm.txt | 258 + arch/arm/Kconfig |2 + drivers/Makefile |2 + drivers/leds/Kconfig | 21 +- drivers/leds/Makefile |2 + drivers/leds/leds-pwm.c| 141 ++ drivers/leds/ledtrig-dim.c | 95 +++ drivers/misc/Kconfig |9 - drivers/misc/Makefile |1 - drivers/misc/atmel_pwm.c | 409 --- drivers/pwm/Kconfig| 24 ++ drivers/pwm/Makefile |6 + drivers/pwm/atmel-pwm.c| 631 + drivers/pwm/pwm.c | 667 include/linux/pwm-led.h| 34 +++ include/linux/pwm.h| 168 ++-- 16 files changed, 2023 insertions(+), 447 deletions(-) create mode 100644 Documentation/pwm.txt create mode 100644 drivers/leds/leds-pwm.c create mode 100644 drivers/leds/ledtrig-dim.c delete mode 100644 drivers/misc/atmel_pwm.c create mode 100644 drivers/pwm/Kconfig create mode 100644 drivers/pwm/Makefile create mode 100644 drivers/pwm/atmel-pwm.c create mode 100644 drivers/pwm/pwm.c create mode 100644 include/linux/pwm-led.h ___ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev