I know there have been discussions about standardizing GPIOs before,
but nothing quite "took". One of the more recent ones was
http://marc.theaimsgroup.com/?l=linux-kernel&m=110873454720555&w=2
Below, find what I think is a useful proposal, trivially implementable on
many ARMs (at91, omap, pxa, ep93xx, ixp2000, pnx4008, davinci, more) as well
as the new AVR32.
Compared to the proposal above, key differences include:
- Only intended for use with "real" GPIOs that work from IRQ context;
e.g. pins on a SOC that are controlled by chip register access.
- Doesn't handle I2C or SPI based GPIOs. I think we actually need
a different API for those "message based" GPIOs, where synchronous
get/set requires sleeping (and is thus unusable from IRQ context).
That API could be used for "real" GPIOs; the converse is not true.
- No IORESOURCE_GPIO resource type (could be added though).
- Can be trivially implemented today, on many systems (see partial
list above) ... no "provider" or gpiochip API necessary.
- Provided in the form of a working patch, with sample implementation;
known to be viable on multiple architectures and platforms.
- Includes Documentation/gpio.txt
Comments?
- Dave
============================ CUT HERE
This defines a simple and minimalist convention for GPIO APIs, and an
implementation of it on one ARM platform (OMAP):
- Documentation/gpio.txt ... describes things (read it)
- include/asm-arm/gpio.h ... defines the ARM hook, which just punts
to <asm/arch/gpio.h> for any implementation
- include/asm-arm/arch-omap/gpio.h ... representative implementation
as a wrapper around existing OMAP-specific GPIO calls
The immediate need for such a cross-architecture API convention is to support
drivers that work the same on AT91 ARM and AVR32 AP7000 chips, which embed many
of the same controllers but have different CPUs.
Signed-off-by: David Brownell <[email protected]>
Index: osk/Documentation/gpio.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/Documentation/gpio.txt 2006-11-11 15:20:58.000000000 -0800
@@ -0,0 +1,233 @@
+GPIO Interfaces
+
+This provides an overview of GPIO access API conventions on Linux.
+
+
+What is a GPIO?
+===============
+A "General Purpose Input/Output" (GPIO) is a flexible software-controlled
+digital signal. They are provided from many kinds of chip, and are familiar
+to Linux developers working with embedded and custom hardware. Each GPIO
+represents a bit connected to a particular pin, or "ball" on Ball Grid Array
+(BGA) packages. Board schematics show which external hardware connects to
+which GPIOs. Drivers can be written generically, so that board setup code
+passes such pin configuration data to drivers.
+
+System-on-Chip (SOC) processors heavily rely on GPIOs. In many cases, every
+non-dedicated pin can be configured as a GPIO; and most chips have at least
+several dozen of them. Programmable logic devices (like FPGAs) can easily
+provide GPIOs, and I2C-connected chips like power managers, audio codecs,
+and "GPIO Expanders" often have a few such pins to help with pin scarcity on
+SOCs. Most PC southbridges have a few dozen GPIO-capable pins.
+
+The exact capabilities of GPIOs vary between systems. Common options:
+
+ - Output values are writable (high=1, low=0). Some chips also have
+ options about how that value is driven, so that for example only one
+ value might be driven ... supporting "wire-OR" and similar schemes
+ for the other value.
+
+ - Input values are likewise readable (1, 0). Some chips support readback
+ of pins configured as "output", which is very useful in such "wire-OR"
+ cases (to support bidirectional signaling). GPIO controllers may have
+ input de-glitch logic, sometimes with software controls.
+
+ - Inputs can often be used as IRQ signals, often edge triggered but
+ sometimes level triggered. Such IRQs may be configurable as system
+ wakeup events, to wake the system from a low power state.
+
+ - Usually a GPIO will be configurable as either input or output, as needed
+ by different product boards; single direction ones exist too.
+
+On a given board each GPIO is used for one specific purpose like monitoring
+MMC/SD card insertion/removal, detecting card writeprotect status, driving
+a LED, configuring a transceiver, and so on.
+
+
+What are the Linux GPIO API conventions?
+========================================
+Note that this is called a "convention" because you don't need to do it this
+way, and it's no crime if you don't. There **are** cases where portability
+is not the main issue; GPIOs are often used for the kind of board-specific
+glue logic that may even change between board revisions, and can't ever be
+used on a board that's wired differently. Also, see the notes later on what
+these conventions omit.
+
+That said, if the convention is supported on their platform, drivers should
+probably use it when possible:
+
+ #include <asm/gpio.h>
+
+If you stick to this convention then it'll be easier for other developers to
+see what your code is doing, and maintain it.
+
+
+Identifying GPIOs
+-----------------
+GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
+reserves "negative" numbers for other purposes like marking signals as
+"not available on this board", or indicating faults.
+
+A given platform defines how it uses those integers. So for example one
+might not use "GPIO 0", instead using numbers 32-159. Another platform
+could use numbers 0..63 with one set of GPIO controllers, 64-79 with a
+different type of GPIO controller, and 80-95 with an FPGA used with one
+particular board family. GPIO numbers are not the same as IRQ numbers;
+see below for calls mapping between the two namespaces.
+
+A given platform may want to define symbols corresponding to GPIO lines,
+primarily for use in board-specific setup code. Most drivers should use
+GPIO numbers passed to them from that setup code, using platform_data to
+hold board-specific pin configuration data (along with other board
+specific data they need).
+
+
+Using GPIOs
+-----------
+One of the first things to do with a GPIO, often in board setup code when
+setting up a platform_device using the GPIO, is mark its direction:
+
+ /* set as input or output, returning 0 or negative errno */
+ int gpio_direction_input(unsigned gpio);
+ int gpio_direction_output(unsigned gpio);
+
+The return value is zero for success, else a negative errno; it must be
+checked, since the main calls don't have error returns.
+
+Setting the direction can fail if the GPIO number is invalid, or when
+that particular GPIO can't be used in that mode. It's generally a bad
+idea to rely on boot firmware to have set the direction correctly, since
+it probably wasn't validated to do more than boot Linux. (Similarly,
+that board setup code probably needs to multiplex that pin as a GPIO,
+and arrange pullups/pulldowns appropriately.)
+
+Driver code will then use this either as an input, or an output. These
+calls can safely be issued from inside IRQ handlers; they don't sleep.
+
+ /* GPIO INPUT: return zero or nonzero */
+ int gpio_get_value(unsigned gpio);
+
+ /* GPIO OUTPUT */
+ void gpio_set_value(unsigned gpio, int value);
+
+The get/set calls have no error returns because "invalid GPIO" would have
+been reported earlier in gpio_set_direction(). The values are boolean,
+zero for low, nonzero for high. When reading the value of an output pin,
+the value returned should be what's seen on the pin ... that won't always
+match the specified output value, because of issues including wire-OR and
+output latencies.
+
+Platform-specific implementations are encouraged to optimise the two
+calls to access the GPIO value in cases where the GPIO number (and for
+output, value) are constant. It's normal for them to need only a couple
+of instructions in such cases (reading or writing a hardware register),
+and not to need spinlocks. Such optimized calls can make bitbanging
+applications a lot more efficient (in both space and time) than spending
+dozens of instructions on subroutine calls.
+
+
+Claiming and Releasing GPIOs (OPTIONAL)
+---------------------------------------
+To help catch system configuration errors, two calls are defined.
+However, many platforms don't currently support this mechanism.
+
+ /* request GPIO, returning 0 or negative errno.
+ * non-null labels may be useful for diagnostics.
+ */
+ int gpio_request(unsigned gpio, const char *label);
+
+ /* release previously-claimed GPIO */
+ void gpio_free(unsigned gpio);
+
+Passing invalid GPIO numbers to gpio_request() will fail, as will requesting
+GPIOs that have already been claimed with that call. The return value of
+gpio_request() must be checked.
+
+These APIs serve two basic purposes. One is marking the signals which
+are actually in use as GPIOs, for better diagnostics; systems may have
+several hundred potential GPIOs, but often only a dozen are used on any
+given board. Another is to catch confusion between drivers, reporting
+errors when drivers wrongly think they have exclusive use of that signal.
+
+These two calls are optional because not not all current Linux platforms
+offer such functionality in their GPIO support; a valid implementation
+could return success for all gpio_request() calls. Unlike the other calls,
+the state they represent doesn't normally match anything from a hardware
+register; it's just a software bitmap which clearly is not necessary for
+correct operation of hardware or (bug free) drivers.
+
+Note that requesting a GPIO does NOT cause it to be configured in any
+way; it just marks that GPIO as in use. Separate code must handle any
+pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
+
+
+Identifying GPIO IRQs
+---------------------
+GPIO numbers are unsigned integers; so are IRQ numbers. These make up
+two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can
+map between them using calls like:
+
+ /* map GPIO numbers to IRQ numbers */
+ int gpio_to_irq(unsigned gpio);
+
+ /* map IRQ numbers to GPIO numbers */
+ int irq_to_gpio(unsigned irq);
+
+Those return either the corresponding number in the other namespace, or
+else a negative errno code if the mapping can't be done. (For example,
+some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
+number that hasn't been marked as an input using gpio_set_direction(), or
+to use an IRQ number that didn't originally come from gpio_to_irq().
+
+These two mapping calls are expected to cost on the order of a single
+addition or subtraction.
+
+Non-error values returned from gpio_to_irq() can be passed to request_irq()
+or free_irq(). They will often be stored into IRQ resources for platform
+devices, by the board-specific initialization code. Note that IRQ trigger
+options are part of the IRQ API, e.g. IRQF_TRIGGER_FALLING, as are system
+wakeup capabilities.
+
+Non-error values returned from irq_to_gpio() would most commonly be used
+with gpio_get_value().
+
+
+
+What do these conventions omit?
+===============================
+These conventions address least-common-denominator functionality, and
+nonportable features are left as platform-specific (but also accessible
+through <asm/gpio.h> inclusion). Some of these may also be configuration
+dependent; the hardware may support reading or writing GPIOs in gangs,
+but only for GPIOs sharing the same bank. (GPIOs are commonly grouped
+in banks of 16 or 32, with a given SOC having several such banks.)
+
+One of the biggest things these conventions omit is pin multiplexing, since
+this is highly chip-specific and nonportable. One platform might not need
+explicit multiplexing; another might have just two options for use of any
+given pin; another might have eight options per pin; another might be able
+to switch a given GPIO to any of several pins. (Yes, those examples all
+come from systems that run Linux today.)
+
+Related to multiplexing is configuration and enabling of the pullups or
+pulldowns integrated on some platforms. Not all platforms support them,
+or support them in the same way; and any given board may use external
+pullups (or pulldowns) so that the on-chip ones should not be used.
+
+There are other system-specific mechanisms that are not specified here,
+like the aforementioned options for input de-glitching and wire-OR output,
+or ganged I/O. Code relying on them will by definition be nonportable.
+
+GPIOs accessed through serial bus chips, like I2C GPIO expanders, are not
+supported here. The main issue with these calls is that reading or writing
+such GPIO values can't be done from IRQ handlers. Reading from an I2C chip
+involves sleeping to get to the head of a message queue (other chips on the
+bus may be using the controller already) and then get the response data;
+writing similarly involves sleeping. A secondary issue is how to address
+GPIOs on those chips; globally assigned unsigned integers are not good
+choices, better ones would look like "GPIO 7 on that chip". Managing the
+IRQs issued by such GPIOs is similarly troublesome.
+
+This API is purely for kernel space, but a userspace API could be built on
+top of it.
+
Index: osk/include/asm-arm/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/include/asm-arm/gpio.h 2006-11-11 14:52:18.000000000 -0800
@@ -0,0 +1,7 @@
+#ifndef _ARCH_ARM_GPIO_H
+#define _ARCH_ARM_GPIO_H
+
+/* not all ARM platforms necessarily support this API ... */
+#include <asm/arch/gpio.h>
+
+#endif /* _ARCH_ARM_GPIO_H */
Index: osk/include/asm-arm/arch-omap/gpio.h
===================================================================
--- osk.orig/include/asm-arm/arch-omap/gpio.h 2006-11-11 14:52:16.000000000 -0800
+++ osk/include/asm-arm/arch-omap/gpio.h 2006-11-11 14:52:18.000000000 -0800
@@ -76,4 +76,58 @@ extern void omap_set_gpio_direction(int
extern void omap_set_gpio_dataout(int gpio, int enable);
extern int omap_get_gpio_datain(int gpio);
+/*-------------------------------------------------------------------------*/
+
+/* wrappers for "new style" GPIO calls. the old OMAP-specfic ones should
+ * eventually be removed (along with this errno.h inclusion), and maybe
+ * gpios should put MPUIOs last too.
+ */
+
+#include <asm/errno.h>
+
+static inline int __must_check gpio_request(unsigned gpio, const char *label)
+ { return omap_request_gpio(gpio); }
+
+static inline void gpio_free(unsigned gpio)
+ { omap_free_gpio(gpio); }
+
+
+static inline int __must_check
+__gpio_set_direction(unsigned gpio, int is_input)
+{
+ if (cpu_class_is_omap2()) {
+ if (gpio > OMAP_MAX_GPIO_LINES)
+ return -EINVAL;
+ } else {
+ if (gpio > (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */))
+ return -EINVAL;
+ }
+ omap_set_gpio_direction(gpio, is_input);
+ return 0;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+ { return __gpio_set_direction(gpio, 1); }
+
+static inline int gpio_direction_output(unsigned gpio)
+ { return __gpio_set_direction(gpio, 0); }
+
+
+static inline int gpio_get_value(unsigned gpio)
+ { return omap_get_gpio_datain(gpio); }
+
+static inline void gpio_set_value(unsigned gpio, int value)
+ { omap_set_gpio_dataout(gpio, value); }
+
+
+static inline int gpio_to_irq(unsigned gpio)
+ { return OMAP_GPIO_IRQ(gpio); }
+
+static inline int irq_to_gpio(unsigned irq)
+{
+ if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
+ return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
+ return irq - IH_GPIO_BASE;
+}
+
#endif
David Brownell wrote:
>
> - Only intended for use with "real" GPIOs that work from IRQ context;
> e.g. pins on a SOC that are controlled by chip register access.
>
> - Doesn't handle I2C or SPI based GPIOs. I think we actually need
> a different API for those "message based" GPIOs, where synchronous
> get/set requires sleeping (and is thus unusable from IRQ context).
> That API could be used for "real" GPIOs; the converse is not true.
>
> - No IORESOURCE_GPIO resource type (could be added though).
>
> - Can be trivially implemented today, on many systems (see partial
> list above) ... no "provider" or gpiochip API necessary.
>
> - Provided in the form of a working patch, with sample implementation;
> known to be viable on multiple architectures and platforms.
>
> - Includes Documentation/gpio.txt
>
> Comments?
>
If this is done, I think it's essential that a "high-level" API (one
that supports message-based GPIO) is provided at the same time. The
"high-level" API should be able to address the GPIOs addressed by the
low-level API. What we do *not* want is a bunch of stuff using the
low-level API when the high-level API would work.
-hpa
On Saturday 11 November 2006 5:27 pm, H. Peter Anvin wrote:
>
> If this is done, I think it's essential that a "high-level" API (one
> that supports message-based GPIO) is provided at the same time.
It's not a "high level" vs "low level" issue, though. There are
dozens to hundreds of drivers that know they're using "real GPIOs",
and which *need* to do that. For example, because the signals must
be accessed while holding a spinlock, or in_irq().
I'd like to see some "message based GPIO" API soonish, but can't buy
the notion that lack of one should be a blocking issue. In fact,
if you go reread that LKML thread I referenced originally, you'll
notice that a key "why this can't fly" issue was that it didn't have
support for irq/spinlock safe GPIOs ... which make up by far the
majority of current GPIO users in Linux.
Lack of arch-neutral "real GPIO" calls is more or less a blocking
issue, given the merge of the AVR32 architecture ... unless you'd
like to argue it's a good thing to make drivers for integrated
controllers be (otherwise needlessly) be arch-specific? One current
example is the "atmel_spi" driver, sharable between AVR32 and AT91;
Atmel reused a lot of the controllers from its AT91 ARM series when
they designed the AVR32 SOCs, and it doesn't make sense to have both
AT91 and AVR32 versions of the same drivers.
> The
> "high-level" API should be able to address the GPIOs addressed by the
> low-level API. What we do *not* want is a bunch of stuff using the
> low-level API when the high-level API would work.
If there were many (any?) drivers that didn't need to care, I might be
tempted to agree. But there aren't ...
Another way to look at it is to notice how many spinlock-safe GPIO
APIs are in use **right now** on ARM ... that's on the order of a
dozen, which is a kind of existence proof that switching to the API in
the patch I sent would be a useful cleanup. (And switching would be
mostly just syntax tweaks ... the primitives are all the same, except
for error checking; their names are just spelled differently.)
Even if there were only four platform specific drivers per architecture
which use GPIOs, that'd still be around 50 drivers that could stop using
arch-specific calls. But some have many more than four, and I know there
are some drivers that never leave arch trees because they have no way to
get rid of platform-specific GPIO usage ...
And on the other side ... how many "message" based ones are there?
Darn few. The pcf8574 driver is unusable by other kernel code, so
every board with a few of those chips has to roll its own solution;
inelegant, but not a burning issue. And the tps65010 driver has a
solution that works OK now too. A max7301 (spi) driver will need
to get a solutition for this too.
I suspect that userspace GPIO accessors should only be written once
though, and they're going to be in the "don't care" category. So
lack of such a "message compatible" GPIO call set might reasonably
hold up merging that sort of (configfs?) interface.
- Dave
David Brownell wrote:
>
> I suspect that userspace GPIO accessors should only be written once
> though, and they're going to be in the "don't care" category. So
> lack of such a "message compatible" GPIO call set might reasonably
> hold up merging that sort of (configfs?) interface.
>
Yes, the userspace interface is by far the biggest issue here.
-hpa
David:
David Brownell wrote:
>I know there have been discussions about standardizing GPIOs before,
>but nothing quite "took". One of the more recent ones was
>
> http://marc.theaimsgroup.com/?l=linux-kernel&m=110873454720555&w=2
>
>Below, find what I think is a useful proposal, trivially implementable on
>many ARMs (at91, omap, pxa, ep93xx, ixp2000, pnx4008, davinci, more) as well
>as the new AVR32.
>
>Compared to the proposal above, key differences include:
>
>
Excellent proposal, I think it should be implemented as-is. I don't
care that this proposal only works for "real" GPIOs, and doesn't provide
for a userspace API.
At its worst, this proposal offers an intermediate step towards a
framework that can do both synchronous/real and asynchronous GPIO
control. At its best, provides a starting point for that framework AND
a much-needed unification in an API that could really use cleaning up
TODAY. No downside, in my opinion.
b.g.
--
Bill Gatliff
[email protected]
On Sat, Nov 11, 2006 at 03:41:32PM -0800, David Brownell wrote:
> I know there have been discussions about standardizing GPIOs before,
> but nothing quite "took". One of the more recent ones was
>
> http://marc.theaimsgroup.com/?l=linux-kernel&m=110873454720555&w=2
>
> Below, find what I think is a useful proposal, trivially implementable on
> many ARMs (at91, omap, pxa, ep93xx, ixp2000, pnx4008, davinci, more) as well
> as the new AVR32.
>
> Compared to the proposal above, key differences include:
>
> - Only intended for use with "real" GPIOs that work from IRQ context;
> e.g. pins on a SOC that are controlled by chip register access.
>
> - Can be trivially implemented today, on many systems (see partial
> list above) ... no "provider" or gpiochip API necessary.
>
> - Provided in the form of a working patch, with sample implementation;
> known to be viable on multiple architectures and platforms.
>
> - Includes Documentation/gpio.txt
>
> Comments?
>
I'm not convinced that exposing the pin number to drivers is the way to
go. The pin numbers themselves are rarely portable across "similar" CPUs
with identical peripherals, while the pin function itself may be
portable (or simply unecessary). Pin muxing also needs to be handled in a
much more transparent and intelligent fashion, which is something else
that is fairly easy to do when looking at a symbolic name for the pin
function rather than the pin # itself.
Exposing the pin # abstraction any higher than the CPU-specific code
hidden away in an architecture backend is just asking for abuse,
specifically for drivers that are shared across different architectures
(or where the peripheral may only be conditionally hooked to a GPIO or
require demuxing).
Any API also needs to allow for multiple GPIO controllers, as it's rarely
just the CPU that has these or needs to manipulate them.
Ok, some ideas:
> I'm not convinced that exposing the pin number to drivers is the way to
> go. The pin numbers themselves are rarely portable across "similar" CPUs
> with identical peripherals, while the pin function itself may be
> portable (or simply unecessary).
I guess that a kind of "name addressing" would be the way to go, we
need to get to it by "location" (I'm thinking PortA 20, PortB 5 rather
than pin number or some other arbitrary convention; we need a way to
not need to look up what 'Port X pin B' should be called.
> Pin muxing also needs to be handled in a
> much more transparent and intelligent fashion, which is something else
> that is fairly easy to do when looking at a symbolic name for the pin
> function rather than the pin # itself.
Seconded
> Any API also needs to allow for multiple GPIO controllers, as it's rarely
> just the CPU that has these or needs to manipulate them.
Agreed, but maybe 'not now'
Another thing that may be considered is the ability to get 'pointers'
for GPIOs. And, of course, protecting GPIOs from concurrent accesses
--
-
Thiago Galesi
Paul:
Paul Mundt wrote:
>I'm not convinced that exposing the pin number to drivers is the way to
>go. The pin numbers themselves are rarely portable across "similar" CPUs
>with identical peripherals, while the pin function itself may be
>portable (or simply unecessary). Pin muxing also needs to be handled in a
>much more transparent and intelligent fashion, which is something else
>that is fairly easy to do when looking at a symbolic name for the pin
>function rather than the pin # itself.
>
>
I don't think he's exporting pin numbers per se. It's more like an
enumeration that comes in from the platform data that the driver passes
back to the GPIO (and, indirectly, the IRQ) API.
>Any API also needs to allow for multiple GPIO controllers, as it's rarely
>just the CPU that has these or needs to manipulate them.
>
>
True, but right now if the "multiple GPIO controllers" are on something
like i2c/spi, they have the synch/asynch issues that Jamey mentioned and
so are by definition out of scope for this proposal. If the GPIO lines
are in an MMIO controller (PLD/FPGA, perhaps), then there's no reason
that the board implementer couldn't address that in their implementation
of the proposed functions.
... except that I bet David is thinking that the implementations will be
in arch/arm/irq-at91rm9200.c or something, and not in
asm/arm/board-xyz.c, so it's the arch implementer's responsibility and
not the platform author's. Yea, I see your point now.
I say that we go with David's proposal for 2.6.19 anyway, and maybe by
2.6.20 we'll have a consensus on how to address that with some
behind-the-API magic. :) (functions added to the machine descriptor,
maybe?)
b.g. , who can't post to the lists at the moment because his ISP is
having a sudden fit of outbound email filter mania.
--
Bill Gatliff
[email protected]
On Mon, Nov 13, 2006 at 12:19:11PM -0600, Bill Gatliff wrote:
> True, but right now if the "multiple GPIO controllers" are on something
> like i2c/spi, they have the synch/asynch issues that Jamey mentioned and
> so are by definition out of scope for this proposal. If the GPIO lines
> are in an MMIO controller (PLD/FPGA, perhaps), then there's no reason
> that the board implementer couldn't address that in their implementation
> of the proposed functions.
>
They're something that has to be accounted for in any sort of API, or we
just end up throwing it all out and starting over again. I was thinking
more of the SuperIO or mfd device scope, where this _is_ a requirement.
> ... except that I bet David is thinking that the implementations will be
> in arch/arm/irq-at91rm9200.c or something, and not in
> asm/arm/board-xyz.c, so it's the arch implementer's responsibility and
> not the platform author's. Yea, I see your point now.
>
The problem with this is that it gets in to something that's getting
close to static pin state configuration. Setting up the mux from platform
code is brain-damage, since it's ultimately up to the system and driver
inserted at the time to grab and configure the pin as necessary, the
board or CPU code is not going to have any notion of the "preferred" pin
state, especially in the heavily muxed case.
> I say that we go with David's proposal for 2.6.19 anyway, and maybe by
> 2.6.20 we'll have a consensus on how to address that with some
> behind-the-API magic. :) (functions added to the machine descriptor,
> maybe?)
>
This is all too late for 2.6.19 regardless. We've gone this long without
a generic API, I see no reason to merge a temporary hack now if it's not
going to be satisfactory for people and require us to throw it all out
and start over again anyways.
I have a real need for supporting multiple controllers and handling
muxing dynamically from various drivers on various architectures, and
anything that exposes the pin # higher than the controller mapping to
function level is never going to work. Drivers have _zero_ interest in
pin #, only in the desired function.
On Monday 13 November 2006 9:38 am, Paul Mundt wrote:
> > Comments?
>
> I'm not convinced that exposing the pin number to drivers is the way to
> go. The pin numbers themselves are rarely portable across "similar" CPUs
> with identical peripherals,
Pin numbers are NOT exposed ... GPIO numbers are. Drivers just get
a number and pass it around. They're cookies with the same kinds of
portability attributes as IRQ numbers and register addresses. (None of
which have particular portability problems when used properly.)
And all those existing ARM GPIO calls work just fine with numbers
for GPIOs. The numbers are platform-specific, sometimes with board
specific additions (like FPGA outputs) ... but they're just numbers.
(And FWIW, I'm more familiar with "balls" like AA12 or J15 being relevant,
than pins like 1 or 332. Of course one could assign numbers to balls,
but the mappings for a BGA-256 would be different from ones on a BGA-193
or a BGA-289. And yet the same logical GPIO -- accessed through the same
software registers -- might be available with all of those packages!
Sometimes on more than one pin. Such issues are associated with pin
mux/config, not GPIO numbering.)
> while the pin function itself may be
> portable (or simply unecessary). Pin muxing also needs to be handled in a
> much more transparent and intelligent fashion, which is something else
> that is fairly easy to do when looking at a symbolic name for the pin
> function rather than the pin # itself.
This is explicitly _not_ addressing pin muxing. The mux configuration on
OMAP1 is different from OMAP2 (the latter is pretty sane!), both are
different from PXA or AT91 or DaVinci, and so on. Pin muxing needs to
happen even when GPIOs are not involved, so the two issues are logically
distinct.
If you'd like to propose a generic pin mux API, more power to you! But
it doesn't seem like a simple problem to me, much less one that needs
solving before a basic GPIO framework could be adopted.
> Exposing the pin # abstraction any higher than the CPU-specific code
> hidden away in an architecture backend is just asking for abuse,
I thought I already said something about that ... yes, here it is:
> > +A given platform may want to define symbols corresponding to GPIO lines,
> > +primarily for use in board-specific setup code. Most drivers should use
> > +GPIO numbers passed to them from that setup code, using platform_data to
> > +hold board-specific pin configuration data (along with other board
> > +specific data they need).
I don't see a disagreement with your comments there, beyond maybe
the fuzziness between CPU/platform/architecture/board ... e.g. on
the same ARM926ejs CPU gets used on many chips with very different
GPIO controllers (which I referred to loosely as "platforms").
> specifically for drivers that are shared across different architectures
> (or where the peripheral may only be conditionally hooked to a GPIO or
> require demuxing).
See above; drivers that are portable -- rather than board-specific,
like a bitbanged I2C or SPI link -- would take GPIO numbers passed
to them from the board setup code.
Of course, such a board-specific bitbanger could know the GPIO as
a constant, not a variable. Which should allow inlinable versions
of the primitives to kick in ... I've observed 2x-4x speedups in
the cases I've measured, just by making gpio get/set directly access
controller registers vs indirecting to short subroutines.
> Any API also needs to allow for multiple GPIO controllers, as it's rarely
> just the CPU that has these or needs to manipulate them.
This API absolutely allows for multiple GPIO controllers ... all it does
is say "here are the numbers, handle them". The platform's implementation
of the API is allowed to map to the relevant controller.
You may be familiar with the way OMAP does it ... the example implementation
(sent with the original post in this thread) copes with two different types
of controller (on OMAP1), one of which has multiple instances as well as
cpu-specific variants (ISTR some having 32 bits per controller, while most
have 16). That isn't exposed in the API. Such issues are implementation
specific, and not all platforms have them.
- Dave
On Monday 13 November 2006 9:56 am, Thiago Galesi wrote:
> I guess that a kind of "name addressing" would be the way to go, we
> need to get to it by "location" (I'm thinking PortA 20, PortB 5 rather
> than pin number or some other arbitrary convention; we need a way to
> not need to look up what 'Port X pin B' should be called.
That's highly platform-specific. AT91 and AVR32 use that style of
addressing ... most others just talk about GPIO numbers. In all cases,
the platform can assign _some_ number to each GPIO signal.
> Another thing that may be considered is the ability to get 'pointers'
> for GPIOs.
The GPIO identifiers are unsigned integers. If you really crave pointers,
you can cast those integers to pointers, and back. But why bother? :)
> And, of course, protecting GPIOs from concurrent accesses
Did you read the proposal? There are *already* two mechanisms for that:
- gpio_request()/gpio_free() ... protecting from concurrent access
between drivers, also known as bugs.
- gpio_set_value() ... implementations can lock internally, as needed.
ditto gpio_get_value(), but only bizarre hardware would need it.
Re that last, consider two different types of GPIO controller:
* One of them has just one register with the output values, and a
RISC CPU without bit set/clear instructions to use on it. So a
spinlock is needed to cover reading the register, modifying that
value, then rewriting the value.
* Better GPIO controller designs (normal ones) have separate registers
for "write mask to set" and "write mask to clear" ... no spinlock
needed, the hardware sorts everything out.
I did update the docs to make clear that gpio get/set calls are atomic;
hard to imagine single bit operations that aren't, but it's worth
removing potential confusion.
- Dave
Paul Mundt wrote:
>On Mon, Nov 13, 2006 at 12:19:11PM -0600, Bill Gatliff wrote:
>
>
>>True, but right now if the "multiple GPIO controllers" are on something
>>like i2c/spi, they have the synch/asynch issues that Jamey mentioned and
>>so are by definition out of scope for this proposal. If the GPIO lines
>>are in an MMIO controller (PLD/FPGA, perhaps), then there's no reason
>>that the board implementer couldn't address that in their implementation
>>of the proposed functions.
>>
>>
>>
>They're something that has to be accounted for in any sort of API, or we
>just end up throwing it all out and starting over again. I was thinking
>more of the SuperIO or mfd device scope, where this _is_ a requirement.
>
>
Right. I don't know anything about SuperIO/SH, but the mfd stuff I've
worked with to date (UCB1400, SM501) all provide for the various
functions by mapping them into existing APIs like i2c, ALSA, etc. which
aren't disturbed by Dave's proposal. They still have their limitations,
i.e. you wouldn't want to put an IDE controller out on one of the GPIO
lines of a UCB1400, a problem that Dave isn't trying to address.
>>... except that I bet David is thinking that the implementations will be
>>in arch/arm/irq-at91rm9200.c or something, and not in
>>asm/arm/board-xyz.c, so it's the arch implementer's responsibility and
>>not the platform author's. Yea, I see your point now.
>>
>>
>>
>The problem with this is that it gets in to something that's getting
>close to static pin state configuration. Setting up the mux from platform
>code is brain-damage, since it's ultimately up to the system and driver
>inserted at the time to grab and configure the pin as necessary, the
>board or CPU code is not going to have any notion of the "preferred" pin
>state, especially in the heavily muxed case.
>
>
The platform _is_ the system, as far as the driver is concerned. I
think they're indistinguishable.
What the driver needs is an enumeration that it can hand to the GPIO
layer that says, "set this high" or "set this low", or "what is the
state on this line?". The platform_device structure is a great place to
pass it the enumerations that, deep in the bowels of the platform/system
code, map into actual GPIO lines. I don't think that's close to static
pin assignment any more than using the platform_device structure to pass
IRQ line enumerations is now. Think: today, most drivers don't know or
care if an IRQ line is edge-triggered or level-triggered. That code is
in the domain of the IRQ subsystem. What David is proposing is the same
sort of thing for GPIO.
>This is all too late for 2.6.19 regardless. We've gone this long without
>a generic API, I see no reason to merge a temporary hack now if it's not
>going to be satisfactory for people and require us to throw it all out
>and start over again anyways.
>
>
I don't see what David is proposing as being a temporary hack. Rather,
it's a starting point. We can add another layer on after the sync/async
issues are sorted out--- which I think is a challenging problem that
will take a while. I'd rather have some uniformity today that we can
use across ARM, and ultimately other arches as well.
>I have a real need for supporting multiple controllers and handling
>muxing dynamically from various drivers on various architectures, and
>anything that exposes the pin # higher than the controller mapping to
>function level is never going to work. Drivers have _zero_ interest in
>pin #, only in the desired function.
>
>
Agreed.
b.g.
--
Bill Gatliff
[email protected]
David Brownell wrote:
>On Monday 13 November 2006 9:38 am, Paul Mundt wrote:
>
>
>
>>>Comments?
>>>
>>>
>>I'm not convinced that exposing the pin number to drivers is the way to
>>go. The pin numbers themselves are rarely portable across "similar" CPUs
>>with identical peripherals,
>>
>>
>
>Pin numbers are NOT exposed ... GPIO numbers are. Drivers just get
>a number and pass it around. They're cookies with the same kinds of
>portability attributes as IRQ numbers and register addresses. (None of
>which have particular portability problems when used properly.)
>
>And all those existing ARM GPIO calls work just fine with numbers
>for GPIOs. The numbers are platform-specific, sometimes with board
>specific additions (like FPGA outputs) ... but they're just numbers.
>
>
>(And FWIW, I'm more familiar with "balls" like AA12 or J15 being relevant,
>than pins like 1 or 332. Of course one could assign numbers to balls,
>but the mappings for a BGA-256 would be different from ones on a BGA-193
>or a BGA-289. And yet the same logical GPIO -- accessed through the same
>software registers -- might be available with all of those packages!
>Sometimes on more than one pin. Such issues are associated with pin
>mux/config, not GPIO numbering.)
>
>
>
Honestly, I'm forced to go to this mentality more every day as well.
The AT91RM9200 is available in at least two packages, not all of which
have the same GPIO mapping (or even available lines!). And don't get me
started on PPC...
>>Any API also needs to allow for multiple GPIO controllers, as it's rarely
>>just the CPU that has these or needs to manipulate them.
>>
>>
>
>This API absolutely allows for multiple GPIO controllers ... all it does
>is say "here are the numbers, handle them". The platform's implementation
>of the API is allowed to map to the relevant controller.
>
>
I think what Paul is saying here is that because your reference
implementation was "arch-omap" instead of "board-<something>", if I add
a PLD with some MMIO GPIO lines then I have to hack global OMAP code.
Maybe we should codify an approach for that now, i.e. add to the
reference implementation some code that hands off out-of-range GPIO
lines to a function in the machine descriptor:
+static inline int gpio_direction_input(unsigned gpio)
+ { if (gpio < OMAP_MAX_ARCH_GPIO) return __gpio_set_direction(gpio, 1);
+ else if(mdesc->platform_gpio_set_direction) platform_gpio_set_direction(gpio, 1); }
... conveniently neglecting the way you find mdesc. :)
I do have a question now. Is there any reason to consider shared GPIO
lines? If so, then the request_gpio() would need a flag GPIO_SHARED or
something.
b.g.
--
Bill Gatliff
[email protected]
David Brownell wrote:
> - gpio_set_value() ... implementations can lock internally, as needed.
> ditto gpio_get_value(), but only bizarre hardware would need it.
>
>
"bizarre" ~= "ppc", at least. But I'd hardly argue with that
characterization most days. :)
b.g.
--
Bill Gatliff
[email protected]
On Monday 13 November 2006 10:38 am, Paul Mundt wrote:
> On Mon, Nov 13, 2006 at 12:19:11PM -0600, Bill Gatliff wrote:
> > True, but right now if the "multiple GPIO controllers" are on something
> > like i2c/spi, they have the synch/asynch issues that Jamey mentioned and
> > so are by definition out of scope for this proposal. If the GPIO lines
> > are in an MMIO controller (PLD/FPGA, perhaps), then there's no reason
> > that the board implementer couldn't address that in their implementation
> > of the proposed functions.
> >
> They're something that has to be accounted for in any sort of API, or we
> just end up throwing it all out and starting over again. I was thinking
> more of the SuperIO or mfd device scope, where this _is_ a requirement.
Could you elaborate on these SuperIO and MFD thingies? Especially with
reference to my point that multiple controllers *are* allowed, and that
this is just a platform-specific issue? (As shown by the fact that the
API works fine with OMAP1, accessing both GPIO and MPUIO controllers
through those API calls ...)
> > ... except that I bet David is thinking that the implementations will be
> > in arch/arm/irq-at91rm9200.c or something, and not in
> > asm/arm/board-xyz.c, so it's the arch implementer's responsibility and
> > not the platform author's. Yea, I see your point now.
>
> The problem with this is that it gets in to something that's getting
> close to static pin state configuration.
I really don't see this at all (see previous email).
> Setting up the mux
... pin mux is 100% out of scope for managing/using GPIOs, since pin mux kicks
in for pins that aren't even GPIO-capable ...
> from platform code is brain-damage,
On the contrary, keeping board-specific pin configuration code out of otherwise
generic/portable device drivers is a Very Good Thing. And that primarily means
moving that code into platform/board specific setup code. (Today's Linux doesn't
have other places to put such code, especially if you don't want to demand much
from typically-sluggish boot loader teams.)
> since it's ultimately up to the system and driver
> inserted at the time to grab and configure the pin as necessary, the
> board or CPU code is not going to have any notion of the "preferred" pin
> state, especially in the heavily muxed case.
I don't see this either.
In the primary "production board" use case, there is absolutely a "preferred"
pin mux config state: each pin is connected to one peripheral in one way.
And typically its configuration is never changed; if it is, that's something
the pin mux API would need to handle. (One example: using a UART's RXD
pin as a wakeup GPIO while the system sleeps. Presumably there are others.)
The only situation where there might not be a "preferred" mode is very much
a secondary use case: the "development board", used to hook up many different
kinds of peripheral hardware. Even in those cases, it makes perfect sense
for Kconfig options to define the _current_ "preferred" mode -- these pins
get muxed for the peripheral that's actually connected today, rather than the
one that we developed two months ago. Because those drivers being developed
are going to be used with a "production board", where costs incurred for
dynamic configuration are undesirable...
> > I say that we go with David's proposal for 2.6.19 anyway, and maybe by
> > 2.6.20 we'll have a consensus on how to address that with some
> > behind-the-API magic. :) (functions added to the machine descriptor,
> > maybe?)
>
> This is all too late for 2.6.19 regardless. We've gone this long without
> a generic API,
I'd be surprised to see it in 2.6.19, but that's what the patch is against;
though I'd not say it's "too late" in any absolute sense, it's certainly a
small and safe enough change (and bigger changes have gone in later).
> I see no reason to merge a temporary hack now if it's not
> going to be satisfactory for people and require us to throw it all out
> and start over again anyways.
You've not shown any technical problems with the proposal though; nothing
about it is a "temporary hack". The functionality in it is clearly
satisfactory enough to work for at least a dozen different platforms,
which are now using similar code. I don't see why you're so negative...
> I have a real need for supporting multiple controllers and handling
> muxing dynamically from various drivers on various architectures, and
> anything that exposes the pin # higher than the controller mapping to
> function level is never going to work. Drivers have _zero_ interest in
> pin #, only in the desired function.
Sure, so what's the problem you have with this then? It doesn't expose
pin numbers, just GPIO numbers. It allows platforms to support multiple
controllers. It doesn't even get in the way of whatever wierd pin mux
setup any given platforms needs. You should be applauding!
- Dave
On Mon, Nov 13, 2006 at 01:29:24PM -0600, Bill Gatliff wrote:
> Paul Mundt wrote:
> >They're something that has to be accounted for in any sort of API, or we
> >just end up throwing it all out and starting over again. I was thinking
> >more of the SuperIO or mfd device scope, where this _is_ a requirement.
>
> Right. I don't know anything about SuperIO/SH, but the mfd stuff I've
> worked with to date (UCB1400, SM501) all provide for the various
> functions by mapping them into existing APIs like i2c, ALSA, etc. which
> aren't disturbed by Dave's proposal. They still have their limitations,
> i.e. you wouldn't want to put an IDE controller out on one of the GPIO
> lines of a UCB1400, a problem that Dave isn't trying to address.
>
Yes, that wasn't my point, my point was that the mfd case itself is
already an example of where we have a real need for multiple GPIO
controllers, today.
> What the driver needs is an enumeration that it can hand to the GPIO
> layer that says, "set this high" or "set this low", or "what is the
> state on this line?". The platform_device structure is a great place to
> pass it the enumerations that, deep in the bowels of the platform/system
> code, map into actual GPIO lines. I don't think that's close to static
> pin assignment any more than using the platform_device structure to pass
> IRQ line enumerations is now.
The "static" configuration is not the GPIO number cookie so much as the
pre-configured state handled at the board-level. This will continue to be
an issue so long as the muxing is decoupled from the rest of the API.
Pin muxing is somewhat of a decoupled issue, but it's quite related when
"GPIO" is just another pin state depending on the mux. The primary
concern here is where we end up doing the refcounting for the pins, so we
don't run in to a situation where a pin is toggled out from an existing
user with regards to drivers contending for pin functions. On the other
hand, I'm not opposed to layering rather than trying to accomodate it all
in the same API.
I have some code for this already, but I suppose I'll have to plug it in
alongside David's API to see whether this will be workable for the use
cases in question.
> Think: today, most drivers don't know or care if an IRQ line is
> edge-triggered or level-triggered. That code is in the domain of the
> IRQ subsystem. What David is proposing is the same sort of thing for
> GPIO.
>
I would suggest that it's exactly the opposite, other than the blatantly
obvious cases (edge-triggered NMI, controllers with fixed detection
logic, etc.) it's _specifically_ up to the drivers to indicate where to
do the detection, as to allow the IRQ controller to adjust the sense
selection for that particular IRQ. Grepping drivers/ for IRQF_TRIGGER is
a pretty good indicator of this.
On Monday 13 November 2006 11:43 am, Bill Gatliff wrote:
> >
> >This API absolutely allows for multiple GPIO controllers ... all it does
> >is say "here are the numbers, handle them". The platform's implementation
> >of the API is allowed to map to the relevant controller.
>
> I think what Paul is saying here is that because your reference
> implementation was "arch-omap" instead of "board-<something>", if I add
> a PLD with some MMIO GPIO lines then I have to hack global OMAP code.
Well, "example" implementation.
Linux doesn't handle PLDs as well as it might. One example in the current
kernel is the original PXA reference platform, Intel's "Lubbock". It's got
an FPGA with essential IRQs. Look at the mess involved in coupling those
IRQs into the system ... not just adding a new irq_chip (easy!), but the
way the global PXA IRQ headers need to know about it.
Part of this is just that NR_IRQs is a global constant, and it's not
possible to allocate new IRQ banks after a kernel is built. Like by
plugging in a few I2C chips with IRQ-capable GPIOs ...
Now, I think the way OMAP handles GPIOs could handle "add an FPGA" pretty
cleanly. That is admittedly a platform-specific implementation issue ...
but then, so is "add an FPGA". And in any case, It should be very clear
that such implementation issues don't need to affect the API, and that
right now only the API is being proposed.
> Maybe we should codify an approach for that now, i.e. add to the
> reference implementation some code that hands off out-of-range GPIO
> lines to a function in the machine descriptor:
>
>
> +static inline int gpio_direction_input(unsigned gpio)
> + { if (gpio < OMAP_MAX_ARCH_GPIO) return __gpio_set_direction(gpio, 1);
> + else if(mdesc->platform_gpio_set_direction) platform_gpio_set_direction(gpio, 1); }
>
>
> ... conveniently neglecting the way you find mdesc. :)
Nah; look at arch/arm/plat-omap/gpio.c and ignore the mess, but observe
that what you see there is essentially a bunch of "gpio controller"
classes using the ugly "switch(type)" dispatch scheme instead of the
prettier "type->op()" dispatch scheme. All that stuff needs to be
cleaner, but for now it'd suffice to add a new FPGA typecode.
> I do have a question now. Is there any reason to consider shared GPIO
> lines? If so, then the request_gpio() would need a flag GPIO_SHARED or
> something.
If two drivers agree to share a line -- how, why? -- they can come to a
private agreement. We lack even a good example of why drivers would
want to share, much less knowledge that it's a general problem!
- Dave
David Brownell wrote:
>On Monday 13 November 2006 11:43 am, Bill Gatliff wrote:
>
>
>>Maybe we should codify an approach for that now, i.e. add to the
>>reference implementation some code that hands off out-of-range GPIO
>>lines to a function in the machine descriptor:
>>
>>
>>+static inline int gpio_direction_input(unsigned gpio)
>>+ { if (gpio < OMAP_MAX_ARCH_GPIO) return __gpio_set_direction(gpio, 1);
>>+ else if(mdesc->platform_gpio_set_direction) platform_gpio_set_direction(gpio, 1); }
>>
>>
>>... conveniently neglecting the way you find mdesc. :)
>>
>>
>
>Nah; look at arch/arm/plat-omap/gpio.c and ignore the mess, but observe
>that what you see there is essentially a bunch of "gpio controller"
>classes using the ugly "switch(type)" dispatch scheme instead of the
>prettier "type->op()" dispatch scheme. All that stuff needs to be
>cleaner, but for now it'd suffice to add a new FPGA typecode.
>
>
Agreed. But if we add to the machine descriptor, then not only do you
not need to touch arch-omap/gpio.c, but you can take that switch
statement out, too. Just one less chunk of code to tweak when a new
platform is supported.
b.g.
--
Bill Gatliff
[email protected]
David Brownell wrote:
>
>Part of this is just that NR_IRQs is a global constant, and it's not
>possible to allocate new IRQ banks after a kernel is built.
>
... because irq_desc is an array, and not a list of some kind.
We have a Virtual File System layer, I guess we need a Virtual Interrupt
System layer too? :)
/me shudders
b.g.
--
Bill Gatliff
[email protected]
On Monday 13 November 2006 12:26 pm, Bill Gatliff wrote:
> >Nah; look at arch/arm/plat-omap/gpio.c and ignore the mess, but observe
> >that what you see there is essentially a bunch of "gpio controller"
> >classes using the ugly "switch(type)" dispatch scheme instead of the
> >prettier "type->op()" dispatch scheme. All that stuff needs to be
> >cleaner, but for now it'd suffice to add a new FPGA typecode.
>
> Agreed. But if we add to the machine descriptor, then not only do you
> not need to touch arch-omap/gpio.c, but you can take that switch
> statement out, too. Just one less chunk of code to tweak when a new
> platform is supported.
Do non-ARM platforms have board/machine descriptors on Linux, though?
I thought most didn't ...
One could come up with an implementation that uses GPIO numbers
as indices into a descriptor array, and using board-specific
initialization of that array ... just like with IRQs and irq_chip.
That could lead to heavier weight implementations than I'd prefer
to see (since GPIOs are a very light weight notion!), but it'd
certainly provide a more reusable way to add GPIO controllers.
All behind the API I proposed, note -- no changes needed.
- Dave
David Brownell wrote:
>On Monday 13 November 2006 12:26 pm, Bill Gatliff wrote:
>
>
>
>>>Nah; look at arch/arm/plat-omap/gpio.c and ignore the mess, but observe
>>>that what you see there is essentially a bunch of "gpio controller"
>>>classes using the ugly "switch(type)" dispatch scheme instead of the
>>>prettier "type->op()" dispatch scheme. All that stuff needs to be
>>>cleaner, but for now it'd suffice to add a new FPGA typecode.
>>>
>>>
>>Agreed. But if we add to the machine descriptor, then not only do you
>>not need to touch arch-omap/gpio.c, but you can take that switch
>>statement out, too. Just one less chunk of code to tweak when a new
>>platform is supported.
>>
>>
>
>Do non-ARM platforms have board/machine descriptors on Linux, though?
>I thought most didn't ...
>
>
PPC does. See arch/ppc/platforms/chestnut.c:platform_init().
>One could come up with an implementation that uses GPIO numbers
>as indices into a descriptor array, and using board-specific
>initialization of that array ... just like with IRQs and irq_chip.
>
>That could lead to heavier weight implementations than I'd prefer
>to see (since GPIOs are a very light weight notion!), but it'd
>certainly provide a more reusable way to add GPIO controllers.
>
>All behind the API I proposed, note -- no changes needed.
>
>
Indeed. I'm all for lightweight, but especially for nice and neat code.
b.g.
--
Bill Gatliff
[email protected]
On Mon, Nov 13, 2006 at 12:00:01PM -0800, David Brownell wrote:
> On Monday 13 November 2006 10:38 am, Paul Mundt wrote:
> > They're something that has to be accounted for in any sort of API, or we
> > just end up throwing it all out and starting over again. I was thinking
> > more of the SuperIO or mfd device scope, where this _is_ a requirement.
>
> Could you elaborate on these SuperIO and MFD thingies? Especially with
> reference to my point that multiple controllers *are* allowed, and that
> this is just a platform-specific issue? (As shown by the fact that the
> API works fine with OMAP1, accessing both GPIO and MPUIO controllers
> through those API calls ...)
>
I think we're talking past each other but effectively in agreement. Bill
was suggesting that multiple controllers were out of scope for the
proposal, which is what I was objecting to. If the API is handling a GPIO
cookie and allows for multiple controllers, I have no objections.
> ... pin mux is 100% out of scope for managing/using GPIOs, since pin
> mux kicks in for pins that aren't even GPIO-capable ...
>
I disagree. Pin muxing kicks in for pins that aren't GPIO-capable, but
for many cases GPIO-capable is just another pin state that can be handled
via muxing. Pin refcounting is obviously not within the scope of your
proposed API (nor should it be), but we do need to allow for pin muxing
to be reconfigured in the GPIO case if nothing else is using the pin in
question that the GPIO maps to. Most of this will be platform specific
and layered, though.
> On the contrary, keeping board-specific pin configuration code out of
> otherwise generic/portable device drivers is a Very Good Thing. And
> that primarily means moving that code into platform/board specific
> setup code. (Today's Linux doesn't have other places to put such code,
> especially if you don't want to demand much from typically-sluggish
> boot loader teams.)
>
This is exactly the sort of static configuration I was referring to.
> > since it's ultimately up to the system and driver
> > inserted at the time to grab and configure the pin as necessary, the
> > board or CPU code is not going to have any notion of the "preferred" pin
> > state, especially in the heavily muxed case.
>
> I don't see this either.
>
> In the primary "production board" use case, there is absolutely a "preferred"
> pin mux config state: each pin is connected to one peripheral in one way.
> And typically its configuration is never changed; if it is, that's something
> the pin mux API would need to handle. (One example: using a UART's RXD
> pin as a wakeup GPIO while the system sleeps. Presumably there are others.)
>
Your definition of "typical" seems to vary considerably from mine. The
typical case more and more is having multiple functions per pin, where a
GPIO state is just another function. If muxing happens within the board
setup code, then we've already effectively locked out the other
functions. This is also not something that can be resolved at build time.
For example, I happen to have a UART RX and an MMC DMA request on the
same pin (GPIO-configured for certain implementations). Both of these can
be provided as modules for a "production" board where the pin can then be
grabbed and toggled depending on which module is inserted, doing any sort
of pin setup on the board side will not help in this case, it's something
that needs to happen higher up.
On Monday 13 November 2006 1:30 pm, Paul Mundt wrote:
> I think we're talking past each other but effectively in agreement. Bill
> was suggesting that multiple controllers were out of scope for the
> proposal, which is what I was objecting to. If the API is handling a GPIO
> cookie and allows for multiple controllers, I have no objections.
It's out of scope in the sense that it doesn't say "here's how to do it".
But it's in-scope in that what it _does_ say makes sure it can be done;
the example implementation does it.
> > ... pin mux is 100% out of scope for managing/using GPIOs, since pin
> > mux kicks in for pins that aren't even GPIO-capable ...
>
> I disagree. Pin muxing kicks in for pins that aren't GPIO-capable, but
> for many cases GPIO-capable is just another pin state that can be handled
> via muxing.
So? You're still confusing GPIOs with pins/balls. They're quite distinct,
in the general case, though maybe not on SH?
Some balls can be used for multiple GPIOs, some GPIOs can be mapped to one
of several balls... there's no general way to infer mux data from knowing
what GPIOs are needed.
> Pin refcounting is obviously not within the scope of your
> proposed API (nor should it be), but we do need to allow for pin muxing
> to be reconfigured in the GPIO case if nothing else is using the pin in
> question that the GPIO maps to. Most of this will be platform specific
> and layered, though.
Well, especially since it will be platform-specific, it can't really
be part of the GPIO framework. I'll repeat the example of OMAP1,
which lets some GPIOs come out on multiple pins ... pin configuration
and GPIOs really **must** be orthogonal. There is just no way to
infer the right mux setup even given a complete list of GPIOS that
will be used. Ditto pullup/pulldown config, multi-drive options,
and so forth.
But it's straightforward to talk about "use <this GPIO> as an input",
and "set <this output GPIO> to high". That doesn't require any
knowledge of how the pins are configured, and is a model that works
with every GPIO controller ever built.
> > > since it's ultimately up to the system and driver
> > > inserted at the time to grab and configure the pin as necessary, the
> > > board or CPU code is not going to have any notion of the "preferred" pin
> > > state, especially in the heavily muxed case.
> >
> > I don't see this either.
> >
> > In the primary "production board" use case, there is absolutely a "preferred"
> > pin mux config state: each pin is connected to one peripheral in one way.
> > And typically its configuration is never changed; if it is, that's something
> > the pin mux API would need to handle. (One example: using a UART's RXD
> > pin as a wakeup GPIO while the system sleeps. Presumably there are others.)
>
> Your definition of "typical" seems to vary considerably from mine.
Maybe. I'm looking at the type of clearly defined system for which
Linux has good support: one board, or a standard board stack; or
sometimes there's PCI-ish autoconfiguration on an expansion bus.
> The
> typical case more and more is having multiple functions per pin, where a
> GPIO state is just another function.
Sure, but that's exactly what I've been saying and isn't in conflict with it.
> If muxing happens within the board
> setup code, then we've already effectively locked out the other
> functions. This is also not something that can be resolved at build time.
See above; if the system is clearly defined, it _can_ be resolved then.
Or at worst, by some platform-specific autoconfiguration scheme.
> For example, I happen to have a UART RX and an MMC DMA request on the
> same pin (GPIO-configured for certain implementations). Both of these can
> be provided as modules for a "production" board where the pin can then be
> grabbed and toggled depending on which module is inserted, doing any sort
> of pin setup on the board side will not help in this case, it's something
> that needs to happen higher up.
You're bringing in a new problem though: autoconfiguring a board stack.
The classic approach is to formalize the module bus and teach that bus how
to enumerate according to the "hotplug" model (like PCI, PNP, etc) ... for
example, consulting an I2C EEPROM with board IDs, with the EEPROM address
depending on which slot it's plugged in to. At the moment you know what
boards are connected, surely you know how to mux those pins ... and what
devices to register, etc.
That's another set of problems that's nicely distinct from GPIOs. :)
- Dave
On Sat, 11 Nov 2006 15:41:32 -0800
David Brownell <[email protected]> wrote:
> Below, find what I think is a useful proposal, trivially
> implementable on many ARMs (at91, omap, pxa, ep93xx, ixp2000,
> pnx4008, davinci, more) as well as the new AVR32.
FYI, here's the AVR32 implementation of the API you propose. Thanks for
writing this up, Dave.
I'm still not sure about how to implement the
gpio_request()/gpio_free() calls, though. Since they're not supposed to
do any port configuration, I think I might convert them to no-ops and
do the allocation (and warn about conflicts) when configuring the port
multiplexer. Since the pin will be configured for one particular usage,
having multiple drivers try to use it will cause problems and handing
it out to the first driver that comes along will not really solve
anything...
Of course, if other arches want gpio_request()/gpio_free(), I'm all for
keeping them.
I'll send you an updated SPI driver using this API after I've tested it
a bit more.
Signed-off-by: Haavard Skinnemoen <[email protected]>
---
arch/avr32/mach-at32ap/pio.c | 103 ++++++++++++++++++++
include/asm-avr32/arch-at32ap/at32ap7000.h | 139 ++++++++++++++++++++++++++++
include/asm-avr32/arch-at32ap/gpio.h | 25 +++++
include/asm-avr32/arch-at32ap/irq.h | 11 ++
include/asm-avr32/gpio.h | 6 +
include/asm-avr32/irq.h | 8 +-
6 files changed, 290 insertions(+), 2 deletions(-)
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index d3aabfc..b6c8b42 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -13,6 +13,7 @@ #include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/portmux.h>
@@ -31,6 +32,21 @@ struct pio_device {
static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
+static struct pio_device *gpio_to_pio(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int index;
+
+ index = gpio >> 5;
+ if (index >= MAX_NR_PIO_DEVICES)
+ return NULL;
+ pio = &pio_dev[index];
+ if (!pio->regs)
+ return NULL;
+
+ return pio;
+}
+
void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
unsigned int function_id)
{
@@ -48,6 +64,93 @@ void portmux_set_func(unsigned int portm
pio_writel(pio, PDR, mask);
}
+/* GPIO API */
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ if (test_and_set_bit(pin, &pio->alloc_mask))
+ return -EBUSY;
+
+ pio_writel(pio, PER, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ BUG_ON(!pio);
+
+ pin = gpio & 0x1f;
+ clear_bit(pin, &pio->alloc_mask);
+}
+EXPORT_SYMBOL(gpio_free);
+
+int gpio_direction_input(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ pio_writel(pio, ODR, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ pio_writel(pio, OER, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned int gpio)
+{
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+
+ return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned int gpio, int value)
+{
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+ u32 mask;
+
+ mask = 1 << (gpio & 0x1f);
+ if (value)
+ pio_writel(pio, SODR, mask);
+ else
+ pio_writel(pio, CODR, mask);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
static int __init pio_probe(struct platform_device *pdev)
{
struct pio_device *pio = NULL;
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
new file mode 100644
index 0000000..b84fdf7
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/at32ap7000.h
@@ -0,0 +1,139 @@
+#ifndef __ASM_ARCH_AT32AP7000_H
+#define __ASM_ARCH_AT32AP7000_H
+
+#define GPIO_PERIPH_A 0
+#define GPIO_PERIPH_B 1
+
+#define NR_GPIO_CONTROLLERS 4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be used as IRQ numbers.
+ */
+#define GPIO_PIOA_BASE (0)
+#define GPIO_PIN_PA0 (GPIO_PIOA_BASE + 0)
+#define GPIO_PIN_PA1 (GPIO_PIOA_BASE + 1)
+#define GPIO_PIN_PA2 (GPIO_PIOA_BASE + 2)
+#define GPIO_PIN_PA3 (GPIO_PIOA_BASE + 3)
+#define GPIO_PIN_PA4 (GPIO_PIOA_BASE + 4)
+#define GPIO_PIN_PA5 (GPIO_PIOA_BASE + 5)
+#define GPIO_PIN_PA6 (GPIO_PIOA_BASE + 6)
+#define GPIO_PIN_PA7 (GPIO_PIOA_BASE + 7)
+#define GPIO_PIN_PA8 (GPIO_PIOA_BASE + 8)
+#define GPIO_PIN_PA9 (GPIO_PIOA_BASE + 9)
+#define GPIO_PIN_PA10 (GPIO_PIOA_BASE + 10)
+#define GPIO_PIN_PA11 (GPIO_PIOA_BASE + 11)
+#define GPIO_PIN_PA12 (GPIO_PIOA_BASE + 12)
+#define GPIO_PIN_PA13 (GPIO_PIOA_BASE + 13)
+#define GPIO_PIN_PA14 (GPIO_PIOA_BASE + 14)
+#define GPIO_PIN_PA15 (GPIO_PIOA_BASE + 15)
+#define GPIO_PIN_PA16 (GPIO_PIOA_BASE + 16)
+#define GPIO_PIN_PA17 (GPIO_PIOA_BASE + 17)
+#define GPIO_PIN_PA18 (GPIO_PIOA_BASE + 18)
+#define GPIO_PIN_PA19 (GPIO_PIOA_BASE + 19)
+#define GPIO_PIN_PA20 (GPIO_PIOA_BASE + 20)
+#define GPIO_PIN_PA21 (GPIO_PIOA_BASE + 21)
+#define GPIO_PIN_PA22 (GPIO_PIOA_BASE + 22)
+#define GPIO_PIN_PA23 (GPIO_PIOA_BASE + 23)
+#define GPIO_PIN_PA24 (GPIO_PIOA_BASE + 24)
+#define GPIO_PIN_PA25 (GPIO_PIOA_BASE + 25)
+#define GPIO_PIN_PA26 (GPIO_PIOA_BASE + 26)
+#define GPIO_PIN_PA27 (GPIO_PIOA_BASE + 27)
+#define GPIO_PIN_PA28 (GPIO_PIOA_BASE + 28)
+#define GPIO_PIN_PA29 (GPIO_PIOA_BASE + 29)
+#define GPIO_PIN_PA30 (GPIO_PIOA_BASE + 30)
+#define GPIO_PIN_PA31 (GPIO_PIOA_BASE + 31)
+
+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
+#define GPIO_PIN_PB0 (GPIO_PIOB_BASE + 0)
+#define GPIO_PIN_PB1 (GPIO_PIOB_BASE + 1)
+#define GPIO_PIN_PB2 (GPIO_PIOB_BASE + 2)
+#define GPIO_PIN_PB3 (GPIO_PIOB_BASE + 3)
+#define GPIO_PIN_PB4 (GPIO_PIOB_BASE + 4)
+#define GPIO_PIN_PB5 (GPIO_PIOB_BASE + 5)
+#define GPIO_PIN_PB6 (GPIO_PIOB_BASE + 6)
+#define GPIO_PIN_PB7 (GPIO_PIOB_BASE + 7)
+#define GPIO_PIN_PB8 (GPIO_PIOB_BASE + 8)
+#define GPIO_PIN_PB9 (GPIO_PIOB_BASE + 9)
+#define GPIO_PIN_PB10 (GPIO_PIOB_BASE + 10)
+#define GPIO_PIN_PB11 (GPIO_PIOB_BASE + 11)
+#define GPIO_PIN_PB12 (GPIO_PIOB_BASE + 12)
+#define GPIO_PIN_PB13 (GPIO_PIOB_BASE + 13)
+#define GPIO_PIN_PB14 (GPIO_PIOB_BASE + 14)
+#define GPIO_PIN_PB15 (GPIO_PIOB_BASE + 15)
+#define GPIO_PIN_PB16 (GPIO_PIOB_BASE + 16)
+#define GPIO_PIN_PB17 (GPIO_PIOB_BASE + 17)
+#define GPIO_PIN_PB18 (GPIO_PIOB_BASE + 18)
+#define GPIO_PIN_PB19 (GPIO_PIOB_BASE + 19)
+#define GPIO_PIN_PB20 (GPIO_PIOB_BASE + 20)
+#define GPIO_PIN_PB21 (GPIO_PIOB_BASE + 21)
+#define GPIO_PIN_PB22 (GPIO_PIOB_BASE + 22)
+#define GPIO_PIN_PB23 (GPIO_PIOB_BASE + 23)
+#define GPIO_PIN_PB24 (GPIO_PIOB_BASE + 24)
+#define GPIO_PIN_PB25 (GPIO_PIOB_BASE + 25)
+#define GPIO_PIN_PB26 (GPIO_PIOB_BASE + 26)
+#define GPIO_PIN_PB27 (GPIO_PIOB_BASE + 27)
+#define GPIO_PIN_PB28 (GPIO_PIOB_BASE + 28)
+#define GPIO_PIN_PB29 (GPIO_PIOB_BASE + 29)
+#define GPIO_PIN_PB30 (GPIO_PIOB_BASE + 30)
+
+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
+#define GPIO_PIN_PC0 (GPIO_PIOC_BASE + 0)
+#define GPIO_PIN_PC1 (GPIO_PIOC_BASE + 1)
+#define GPIO_PIN_PC2 (GPIO_PIOC_BASE + 2)
+#define GPIO_PIN_PC3 (GPIO_PIOC_BASE + 3)
+#define GPIO_PIN_PC4 (GPIO_PIOC_BASE + 4)
+#define GPIO_PIN_PC5 (GPIO_PIOC_BASE + 5)
+#define GPIO_PIN_PC6 (GPIO_PIOC_BASE + 6)
+#define GPIO_PIN_PC7 (GPIO_PIOC_BASE + 7)
+#define GPIO_PIN_PC8 (GPIO_PIOC_BASE + 8)
+#define GPIO_PIN_PC9 (GPIO_PIOC_BASE + 9)
+#define GPIO_PIN_PC10 (GPIO_PIOC_BASE + 10)
+#define GPIO_PIN_PC11 (GPIO_PIOC_BASE + 11)
+#define GPIO_PIN_PC12 (GPIO_PIOC_BASE + 12)
+#define GPIO_PIN_PC13 (GPIO_PIOC_BASE + 13)
+#define GPIO_PIN_PC14 (GPIO_PIOC_BASE + 14)
+#define GPIO_PIN_PC15 (GPIO_PIOC_BASE + 15)
+#define GPIO_PIN_PC16 (GPIO_PIOC_BASE + 16)
+#define GPIO_PIN_PC17 (GPIO_PIOC_BASE + 17)
+#define GPIO_PIN_PC18 (GPIO_PIOC_BASE + 18)
+#define GPIO_PIN_PC19 (GPIO_PIOC_BASE + 19)
+#define GPIO_PIN_PC20 (GPIO_PIOC_BASE + 20)
+#define GPIO_PIN_PC21 (GPIO_PIOC_BASE + 21)
+#define GPIO_PIN_PC22 (GPIO_PIOC_BASE + 22)
+#define GPIO_PIN_PC23 (GPIO_PIOC_BASE + 23)
+#define GPIO_PIN_PC24 (GPIO_PIOC_BASE + 24)
+#define GPIO_PIN_PC25 (GPIO_PIOC_BASE + 25)
+#define GPIO_PIN_PC26 (GPIO_PIOC_BASE + 26)
+#define GPIO_PIN_PC27 (GPIO_PIOC_BASE + 27)
+#define GPIO_PIN_PC28 (GPIO_PIOC_BASE + 28)
+#define GPIO_PIN_PC29 (GPIO_PIOC_BASE + 29)
+#define GPIO_PIN_PC30 (GPIO_PIOC_BASE + 30)
+#define GPIO_PIN_PC31 (GPIO_PIOC_BASE + 31)
+
+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
+#define GPIO_PIN_PD0 (GPIO_PIOD_BASE + 0)
+#define GPIO_PIN_PD1 (GPIO_PIOD_BASE + 1)
+#define GPIO_PIN_PD2 (GPIO_PIOD_BASE + 2)
+#define GPIO_PIN_PD3 (GPIO_PIOD_BASE + 3)
+#define GPIO_PIN_PD4 (GPIO_PIOD_BASE + 4)
+#define GPIO_PIN_PD5 (GPIO_PIOD_BASE + 5)
+#define GPIO_PIN_PD6 (GPIO_PIOD_BASE + 6)
+#define GPIO_PIN_PD7 (GPIO_PIOD_BASE + 7)
+#define GPIO_PIN_PD8 (GPIO_PIOD_BASE + 8)
+#define GPIO_PIN_PD9 (GPIO_PIOD_BASE + 9)
+#define GPIO_PIN_PD10 (GPIO_PIOD_BASE + 10)
+#define GPIO_PIN_PD11 (GPIO_PIOD_BASE + 11)
+#define GPIO_PIN_PD12 (GPIO_PIOD_BASE + 12)
+#define GPIO_PIN_PD13 (GPIO_PIOD_BASE + 13)
+#define GPIO_PIN_PD14 (GPIO_PIOD_BASE + 14)
+#define GPIO_PIN_PD15 (GPIO_PIOD_BASE + 15)
+#define GPIO_PIN_PD16 (GPIO_PIOD_BASE + 16)
+#define GPIO_PIN_PD17 (GPIO_PIOD_BASE + 17)
+
+/*
+ * Technically, PIOE is also available, but we'll leave it alone since
+ * the SDRAM interface depends on it.
+ */
+
+#endif /* __ASM_ARCH_AT32AP7000_H */
diff --git a/include/asm-avr32/arch-at32ap/gpio.h b/include/asm-avr32/arch-at32ap/gpio.h
new file mode 100644
index 0000000..411a686
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/gpio.h
@@ -0,0 +1,25 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <linux/compiler.h>
+#include <asm/irq.h>
+
+int __must_check gpio_request(unsigned int gpio, const char *label);
+void gpio_free(unsigned int gpio);
+
+int gpio_direction_input(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio);
+int gpio_get_value(unsigned int gpio);
+void gpio_set_value(unsigned int gpio, int value);
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return gpio + GPIO_IRQ_BASE;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return irq - GPIO_IRQ_BASE;
+}
+
+#endif /* __ASM_AVR32_GPIO_H */
diff --git a/include/asm-avr32/arch-at32ap/irq.h b/include/asm-avr32/arch-at32ap/irq.h
new file mode 100644
index 0000000..1e2513e
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/irq.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_AVR32_ARCH_IRQ_H
+#define __ASM_AVR32_ARCH_IRQ_H
+
+#define EIM_IRQ_BASE NR_INTERNAL_IRQS
+#define NR_EIM_IRQS 32
+#define GPIO_IRQ_BASE (EIM_IRQ_BASE + NR_EIM_IRQS)
+#define NR_GPIO_IRQS (4 * 32)
+
+#define NR_IRQS (GPIO_IRQ_BASE + NR_GPIO_IRQS)
+
+#endif /* __ASM_AVR32_ARCH_IRQ_H */
diff --git a/include/asm-avr32/gpio.h b/include/asm-avr32/gpio.h
new file mode 100644
index 0000000..19e8ccc
--- /dev/null
+++ b/include/asm-avr32/gpio.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <asm/arch/gpio.h>
+
+#endif /* __ASM_AVR32_GPIO_H */
diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
index f7e7257..83e6549 100644
--- a/include/asm-avr32/irq.h
+++ b/include/asm-avr32/irq.h
@@ -2,8 +2,12 @@ #ifndef __ASM_AVR32_IRQ_H
#define __ASM_AVR32_IRQ_H
#define NR_INTERNAL_IRQS 64
-#define NR_EXTERNAL_IRQS 64
-#define NR_IRQS (NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS)
+
+#include <asm/arch/irq.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS (NR_INTERNAL_IRQS)
+#endif
#define irq_canonicalize(i) (i)
--
1.4.3.2
On Monday 13 November 2006 12:15 pm, Paul Mundt wrote:
> On Mon, Nov 13, 2006 at 01:29:24PM -0600, Bill Gatliff wrote:
>
> Pin muxing is somewhat of a decoupled issue,
I'll continue to read that as "100% orthogonal to any GPIO API since it's
so thoroughly platform-specific". :)
> but it's quite related when
> "GPIO" is just another pin state depending on the mux. The primary
> concern here is where we end up doing the refcounting for the pins, so we
> don't run in to a situation where a pin is toggled out from an existing
> user with regards to drivers contending for pin functions.
A fine example of two platform-specific notions. First, that GPIO signals
are muxed in that way ... they could easily have dedicated pins!! Second,
that there's even a one-to-one association between pins and GPIOs ... I'll
repeat the previous example of OMAP1, where certain GPIOs could come out on
any of several pins. And where some pins can be muxed to work with more
than one GPIO (but only one at a time, of course). Clearly, neither pin
refcounting nor GPIO claiming can be sufficient to prevent such problems ...
Another issue that's orthogonal to a GPIO API is IRQ trigger modes:
> > Think: today, most drivers don't know or care if an IRQ line is
> > edge-triggered or level-triggered. That code is in the domain of the
> > IRQ subsystem. What David is proposing is the same sort of thing for
> > GPIO.
> >
> I would suggest that it's exactly the opposite, other than the blatantly
> obvious cases (edge-triggered NMI, controllers with fixed detection
> logic, etc.) it's _specifically_ up to the drivers to indicate where to
> do the detection, as to allow the IRQ controller to adjust the sense
> selection for that particular IRQ. Grepping drivers/ for IRQF_TRIGGER is
> a pretty good indicator of this.
It's easy to think that way, but then it's just as easy to assemble boards
that happen to route IRQs through an inverting buffer because of signal
level or strength issues. And with discrete controllers, I've certainly
had to cope with drivers running on systems that don't support the ideal
triggering mode ... typically there'd be an edge trigger mode (e.g. only
"both edges" supported) for a chip whose IRQ is active low.
It's better to make the board setup include the right IRQ triggering mode
for each IRQ, so that drivers don't have to embed board-specific knowledge
like that. It's bad enough to have to write the driver to cope with some
unnatural trigger mode ... but it's really rude to make them have to try
guess several times before they can find which one works!!
Boards can pass the IORESOURCE_IRQ_* flags in irq resources, though it
seems not many do.
- Dave
On Thursday 16 November 2006 6:54 am, Haavard Skinnemoen wrote:
> On Sat, 11 Nov 2006 15:41:32 -0800
> David Brownell <[email protected]> wrote:
>
> > Below, find what I think is a useful proposal, trivially
> > implementable on many ARMs (at91, omap, pxa, ep93xx, ixp2000,
> > pnx4008, davinci, more) as well as the new AVR32.
>
> FYI, here's the AVR32 implementation of the API you propose. Thanks for
> writing this up, Dave.
>
> I'm still not sure about how to implement the
> gpio_request()/gpio_free() calls, though.
Simplest would be to manipulate a bitmask:
gpio_request() --> return test_and_set_bit(...) ? -EBUSY : 0;
gpio_free() --> clear_bit(...)
Or if you want to track the identifiers and provide a debugfs dump
of the active GPIOs and their status, use an array of strings (and
spinlock its updates) or nuls as "fat bits", instead of a bit array.
> Since they're not supposed to
> do any port configuration, I think I might convert them to no-ops and
> do the allocation (and warn about conflicts) when configuring the port
> multiplexer.
What they're supposed to do is report conflicts between two
drivers which both think they own the GPIO ... as errors.
That's different from pin mux setup, which for most embedded
systems is just making sure the SOC is configured to match
what Linux expects. The boot loader usualy does some of that,
but it's probably not validated to do more than reliably boot
an operating system ... so pin muxing can't realistically
report anything as an error. At best, it's a suggestion to
update the bootloader someday.
> Since the pin will be configured for one particular usage,
> having multiple drivers try to use it will cause problems and handing
> it out to the first driver that comes along will not really solve
> anything...
No, but letting the second one report the fatal error is a big help.
And heck, you've got reasonable chance the first driver will work,
if the second doesn't interfere with it! (Or maybe it's the other
way around. At least you'd have logged a fatal error message ...)
> Of course, if other arches want gpio_request()/gpio_free(), I'm all for
> keeping them.
I thought you were someone who _wanted_ this mechanism?
Or were you instead thinking of a pin mux mechanism?
There can be no arch-neutral pin muxing that takes just
a GPIO number as input (which is how gpio_request works).
The reason is that there are platforms which need muxing,
and which have multiple options as to which pin a given
GPIO goes out on (and contrariwise, which GPIO is coupled
to a given pin).
> +int gpio_request(unsigned int gpio, const char *label)
> +{
> + struct pio_device *pio;
> + unsigned int pin;
> +
> + pio = gpio_to_pio(gpio);
> + if (!pio)
> + return -ENODEV;
> +
> + pin = gpio & 0x1f;
> + if (test_and_set_bit(pin, &pio->alloc_mask))
> + return -EBUSY;
> +
> + pio_writel(pio, PER, 1 << pin);
Enabling the pin as a GPIO is a pin mux responsibility, not
a "keep drivers from stepping all over each other" thing.
Admittedly, the GPIO controller in those Atmel chips (AVR32,
AT91) does have a one-to-one mapping for muxable pins and GPIOs,
but that's not a portable notion.
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(gpio_request);
> +
> +void gpio_free(unsigned int gpio)
> +{
> + struct pio_device *pio;
> + unsigned int pin;
> +
> + pio = gpio_to_pio(gpio);
> + BUG_ON(!pio);
Don't use BUG_ON in new code ... in this case it'd be best to just
warn and return. Notice by the way that this isn't an inverse of
the gpio_request(), since you aren't taking the pin back from the
GPIO controller.
> +#define GPIO_PIOA_BASE (0)
> +#define GPIO_PIN_PA0 (GPIO_PIOA_BASE + 0)
> +#define GPIO_PIN_PA1 (GPIO_PIOA_BASE + 1)
> +#define GPIO_PIN_PA2 (GPIO_PIOA_BASE + 2)
> ...
Someone had the suggestion to reduce the number of #defines
by doing someting like
#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
I kind of like that, even if it's not such a direct match to
Atmel's documentation.
> --- /dev/null
> +++ b/include/asm-avr32/arch-at32ap/gpio.h
> @@ -0,0 +1,25 @@
> +#ifndef __ASM_AVR32_GPIO_H
> +#define __ASM_AVR32_GPIO_H
> +
> +#include <linux/compiler.h>
> +#include <asm/irq.h>
> +
> +int __must_check gpio_request(unsigned int gpio, const char *label);
> +void gpio_free(unsigned int gpio);
> +
> +int gpio_direction_input(unsigned int gpio);
> +int gpio_direction_output(unsigned int gpio);
> +int gpio_get_value(unsigned int gpio);
> +void gpio_set_value(unsigned int gpio, int value);
> +
> +static inline int gpio_to_irq(unsigned int gpio)
> +{
> + return gpio + GPIO_IRQ_BASE;
> +}
> +
> +static inline int irq_to_gpio(unsigned int irq)
> +{
> + return irq - GPIO_IRQ_BASE;
> +}
> +
> +#endif /* __ASM_AVR32_GPIO_H */
Aren't you going to want to add AVR-specific extensions so that
drivers (or more typically, board init code) can manage pullups
and input de-glitching?
- Dave
OK, just trying to summarize here:
- Nobody has reported **ANY** real problem with the API, other than a minor
comment from Andrew Victor about a must_check annotation (resolved in a
nyet-posted update). No surprise; there are already nearly a dozen APIs
in the kernel doing exactly the same thing.
- Various folk want to see an additional API that can work with things like
I2C GPIO expanders ... where the bit get/set calls require task contexts.
Everyone agrees such a thing is eventually needed, but nobody needs it
"today".
- There's interest in a userspace interface to GPIOs; nothing pressing, and
that's at a different level, but worth noting since it always comes up.
- Paul Mundt also wants to see pin muxing APIs. Fine, but that's both
orthogonal and highly platform-specific. I can't support trying to
merge it into the generic notion of a GPIO line.
- Paul also wants to see implementations package multiple sync/atomic GPIO
controllers using this API. The API that I pulled together clearly permits
implementations to do that ... but it does not require them to do so.
I could certainly take all that feedback and let it lead me to some particular
implementation -- example, a table of { controller, index, flags } structs indexed
by the GPIO numbers, with controller ops vectors matching the primitives -- but
even if that were to happen, I'd like to know if anyone has any major disagreement
with the summary above.
- Dave
David Brownell wrote:
>I could certainly take all that feedback and let it lead me to some particular
>implementation -- example, a table of { controller, index, flags } structs indexed
>by the GPIO numbers, with controller ops vectors matching the primitives -- but
>even if that were to happen, I'd like to know if anyone has any major disagreement
>with the summary above.
>
>
Your summary agrees with me.
b.g.
--
Bill Gatliff
[email protected]
David Brownell wrote:
>That's different from pin mux setup, which for most embedded
>systems is just making sure the SOC is configured to match
>what Linux expects. The boot loader usualy does some of that,
>but it's probably not validated to do more than reliably boot
>an operating system ... so pin muxing can't realistically
>report anything as an error. At best, it's a suggestion to
>update the bootloader someday.
>
>
The ARM platforms I've worked with provide enough read-only information
to allow you to report the status/assignment of a GPIO line, be it
input, output, or assigned to one of several peripheral functions. So
you definitely want to read that stuff and report from it rather than
just the state of a static array somewhere.
In fact, at least at first glance there's really no need for a static
array at all on many chips that I can think of. At most, the
gpio_request() function should build up a temporary bitmask using
information read from the hardware, then discard that temporary bitmask
after the request is completed and the hardware actually configured.
>No, but letting the second one report the fatal error is a big help.
>And heck, you've got reasonable chance the first driver will work,
>if the second doesn't interfere with it! (Or maybe it's the other
>way around. At least you'd have logged a fatal error message ...)
>
>
If the gpio_request() is reading from the hardware, it could determine
that a GPIO line was assigned to a peripheral function by the
bootloader; then it could refuse that request to the caller. The fact
that we don't have an API to assign the pin to a peripheral function
would be even less of a concern then, because ordinary GPIO users of the
pin could still avoid accidentally assigning a peripheral function pin
to themselves as GPIO.
>Admittedly, the GPIO controller in those Atmel chips (AVR32,
>AT91) does have a one-to-one mapping for muxable pins and GPIOs,
>but that's not a portable notion.
>
>
Can you refer me to a specific chip that is contrary to the AVR32/AT91
notion, so that I can be sure I'm understanding what you're saying?
b.g.
--
Bill Gatliff
[email protected]
David Brownell wrote:
>A fine example of two platform-specific notions. First, that GPIO signals
>are muxed in that way ... they could easily have dedicated pins!! Second,
>that there's even a one-to-one association between pins and GPIOs ... I'll
>repeat the previous example of OMAP1, where certain GPIOs could come out on
>any of several pins. And where some pins can be muxed to work with more
>than one GPIO (but only one at a time, of course). Clearly, neither pin
>refcounting nor GPIO claiming can be sufficient to prevent such problems ...
>
>
So, you're saying that if GPIOA1 can come out on pins ZZ1 and BB6, then
there would be two unique "GPIO numbers", one for each possibility?
b.g.
--
Bill Gatliff
[email protected]
On Monday 20 November 2006 7:44 pm, Bill Gatliff wrote:
> David Brownell wrote:
>
> >A fine example of two platform-specific notions. First, that GPIO signals
> >are muxed in that way ... they could easily have dedicated pins!! Second,
> >that there's even a one-to-one association between pins and GPIOs ... I'll
> >repeat the previous example of OMAP1, where certain GPIOs could come out on
> >any of several pins. And where some pins can be muxed to work with more
> >than one GPIO (but only one at a time, of course). Clearly, neither pin
> >refcounting nor GPIO claiming can be sufficient to prevent such problems ...
> >
>
> So, you're saying that if GPIOA1 can come out on pins ZZ1 and BB6, then
> there would be two unique "GPIO numbers", one for each possibility?
No; one number, since it's controlled by the same set of bits in the GPIO
controller (e.g. bit 12 in the registers of bank 3) regardless of how the
signals are routed out through pins. That's my point: GPIO number need
not imply a particular pin, and vice versa.
Have a look at table 2-5 starting on page 81 of the OMAP 5912 datasheet
("Rev E", omap5912.pdf) linked at the top of
http://focus.ti.com/docs/prod/folders/print/omap5912.html
GPIOs start at p. 91; there are four banks of GPIO controllers, 16 gpios
each, and also a bank of MPUIOs starting at p. 95 ... half the MPUIO pins
can come out on two different balls, some of the GPIOs can be routed to any
of three different balls. (A omap5912 is more or less an omap1611, fyi.)
So regardless of whether GPIO_62 is routed to ball M7 or G20, it's still
going to use number 62, which is bit 14 in various registers of the GPIO4
module, starting at 0xfffbb400 ... and for good fun, the muxing API will
refer to the balls on the (smaller) ZZG package even if your board uses
the larger ZDY package (so your schematics might say J5 not M7, that table
is very handy in such cases).
And if you consult table 2-2 on pg. 33 you'll be able to notice things
like ball R13 working for either MPUIO_0 or GPIO_36, ball V10 working
for MPUIO_10 or MPUIO_7, and so on.
- Dave
On Monday 20 November 2006 7:11 pm, Bill Gatliff wrote:
>
> In fact, at least at first glance there's really no need for a static
> array at all on many chips that I can think of. At most, the
> gpio_request() function should build up a temporary bitmask using
> information read from the hardware, then discard that temporary bitmask
> after the request is completed and the hardware actually configured.
Let's go back to what gpio_request() is defined to do, though: it very
explicitly "does NOT cause it to be configured in any way", and succeeds
unless the specified GPIO has "already been claimed".
It's addressing problems related only to software configuration:
> + These APIs serve two basic purposes. One is marking the signals which
> + are actually in use as GPIOs, for better diagnostics; systems may have
> + several hundred potential GPIOs, but often only a dozen are used on any
> + given board. Another is to catch confusion between drivers, reporting
> + errors when drivers wrongly think they have exclusive use of that signal.
Example, it's a bug if two drivers both thinking they manage GPIO 17.
> >No, but letting the second one report the fatal error is a big help.
> >And heck, you've got reasonable chance the first driver will work,
> >if the second doesn't interfere with it! (Or maybe it's the other
> >way around. At least you'd have logged a fatal error message ...)
> >
> >
>
> If the gpio_request() is reading from the hardware,
... which it must not do ...
> it could determine
> that a GPIO line was assigned to a peripheral function by the
> bootloader;
On AT91, and AVR32, yes ... since those GPIO controllers are also
involved in pin muxing, and they use a very simple mux model.
(And if the pin were assigned as a GPIO, or not ... so what? That
doesn't mean that's how Linux must use it.)
But in general, no ... the general case is that GPIO controller(s)
and pin muxing are two separate units in the silicon, and there's
no one-to-one coupling possible.
> >Admittedly, the GPIO controller in those Atmel chips (AVR32,
> >AT91) does have a one-to-one mapping for muxable pins and GPIOs,
> >but that's not a portable notion.
> >
> >
>
> Can you refer me to a specific chip that is contrary to the AVR32/AT91
> notion, so that I can be sure I'm understanding what you're saying?
See my previous email, which gives detailed and very specific examples
with respect to OMAP 5912 chips you get overnight from e.g. Digikey,
and where the pin-to-gpio mapping space is many-to-many.
- Dave
David Brownell wrote:
>On Monday 20 November 2006 7:44 pm, Bill Gatliff wrote:
>
>
>>So, you're saying that if GPIOA1 can come out on pins ZZ1 and BB6, then
>>there would be two unique "GPIO numbers", one for each possibility?
>>
>>
>
>No; one number, since it's controlled by the same set of bits in the GPIO
>controller (e.g. bit 12 in the registers of bank 3) regardless of how the
>signals are routed out through pins. That's my point: GPIO number need
>not imply a particular pin, and vice versa.
>
>
Ok, thanks for the OMAP stuff. I think I can understand now.
Why not have GPIO numbers refer to unique combinations of GPIO+pin? If
the GPIO line is tied to a piece of external hardware, that connection
is surely through a specific pin. So it seems like you'd need GPIO+pin
every time there was an option.
>So regardless of whether GPIO_62 is routed to ball M7 or G20, it's still
>going to use number 62, which is bit 14 in various registers of the GPIO4
>module, starting at 0xfffbb400 ... and for good fun, the muxing API will
>refer to the balls on the (smaller) ZZG package even if your board uses
>the larger ZDY package (so your schematics might say J5 not M7, that table
>is very handy in such cases).
>
>
Yikes! :)
Explain to me why having GPIO enumerations map to unique GPIO+pin
combinations would be a bad idea in this case? It seems like the point
here is to help a driver find and assert their GPIO _pin_ so that the
driver can can talk to the attached external hardware. Having an
enumeration "GPIO62M7" would be a handy way to do that. Maybe the
enumeration is actually defined as ((0x400 << 16) | (14 << 8) | 4), or
some other encoding that makes it easy in the implementation of
gpio_XXX() to find the right registers and get the routing set up
correctly. It's just an opaque, magic number to the driver after all.
And since GPIOs are arch/mach/board-specific anyway, who would care if
OMAP was the only system that had an enumeration called "GPIO62M7"?
When other boards set up their platform_struct, they'd use the
enumerations available for that platform. "GPIOA1" in systems where
that GPIO line could only go to one pin per the datasheet, for example.
b.g.
--
Bill Gatliff
[email protected]
On Monday 20 November 2006 9:09 pm, Bill Gatliff wrote:
> Why not have GPIO numbers refer to unique combinations of GPIO+pin?
That sounds unduly complicated compared to just using the GPIO numbers
which are used throughout the hardware and software docs. It'd also
be a big (and needless) disruption to code that's been working fine for
several years now ... and there'd need to be some scheme to recognize
that most GPIO numbers suddenly become invalid (since the space would
become large and sparsely populated, vs small and dense).
Maybe if it were being done over from scratch, that'd be workable.
But at this point I have a hard time seeing anyone want to change,
even if there were a better argument.
> If the GPIO line is tied to a piece of external hardware, that connection
> is surely through a specific pin. So it seems like you'd need GPIO+pin
> every time there was an option.
Pin muxing is set up once, early, and from then on it suffices to use
the GPIO number. The mux problems are orthogonal to GPIOs.
> It seems like the point
> here is to help a driver find and assert their GPIO _pin_ so that the
> driver can can talk to the attached external hardware.
Updating the GPIO controller is always (all architectures!) done in terms
of a number mapping to some controller and a bit number, not a pin. The
drivers never care about pins.
The only thing that cares about pins is board setup code -- briefly.
- Dave
David Brownell wrote:
>But in general, no ... the general case is that GPIO controller(s)
>and pin muxing are two separate units in the silicon, and there's
>no one-to-one coupling possible.
>
>
Not sure I believe that there's "no one-to-one coupling possible"
anymore. :)
In OMAP, as far as I can tell after skimming the datasheet (and being
reminded why I avoid TI's microcontrollers!), someone has to set up the
MUX so that a given GPIO can get to a specified pin. And practically
speaking, what's soldered to a pin is nearly immutable for a given board
(or at least a particular revision; you won't change it in software
anyway!). So for sanity's sake the GPIO "resource manager" would have
to refuse a request for a GPIO line assigned to a pin that had already
been committed to something else, be it another GPIO line or a
peripheral function. So I think having the notion of a resource manager
_at all_ implies that you're into some amount of MUX analysis/management
on machines that have them.
Aside: You state that there are many-to-many possibilities. In theory
yes, but for OMAP and any other practical machine, no. You never have
an infinite number of pins or GPIOs, so even with some kind of radical
"switch fabric" the number of unique combinations of GPIO+pin still
would be bounded. In the case of OMAP, it looks like most of the GPIOs
can be assigned to one of two pins, and each pin can be assigned to one
of two GPIOs. So, "some-to-some". :)
The "multiplexing" that I was wishing to leave out of the GPIO API was
the part where you assign pins to peripheral functions *or* GPIO, a'la
AT91. The existing kernel code for that chip provides a number of
functions to help board authors get all the routing and configuration
right for each pin ("peripheral A function, or peripheral B, or GPIO?
Input, or output? Pullup resistor, or no? Input filtering, or no?")
(*). I'm ok with not trying to consolidate that functionality in an
arch-neutral GPIO-only API right now, since machines do that so differently.
But I was assuming all along that we were overloading the notion of a
"gpio number" enumeration, such that each enumeration ultimately
referred to a unique combination of GPIO+pin for the instant machine.
And once you've got that, there's no reason why the underlying
implementation couldn't assert the proper routing at the time a specific
GPIO+pin was requested. Maybe that's up to the individual authors as to
whether they want to provide this in their implementations, or choose
instead to leave out the MUX configuration and just map GPIO
enumerations to physical GPIO line numbers (and hope for the best at
runtime). But I still don't see a reason why they shouldn't if they're
willing to do the code.
Sorry to recycle on all of this again. Maybe I'm just a slow learner,
maybe I just was misunderstanding some of the terminology we were
throwing around. Maybe it's something else entirely.
* - Most of which was written by Dave Brownell. Thanks!
b.g.
--
Bill Gatliff
[email protected]
On Mon, Nov 20, 2006 at 09:35:38PM -0800, David Brownell wrote:
> On Monday 20 November 2006 9:09 pm, Bill Gatliff wrote:
> > It seems like the point
> > here is to help a driver find and assert their GPIO _pin_ so that the
> > driver can can talk to the attached external hardware.
>
> Updating the GPIO controller is always (all architectures!) done in terms
> of a number mapping to some controller and a bit number, not a pin. The
> drivers never care about pins.
>
> The only thing that cares about pins is board setup code -- briefly.
>
That's rather simplifying things. The driver using the GPIO number isn't
going to care about the pin number that it's associated with, but that's
not to say that another driver won't have an interest in the alternate
function of the pin that the GPIO is tied to, while the first driver is
expecting it to be used as a GPIO.
There is a need to layer a pin mux API underneath the GPIO API to deal
with these sorts of things, but that's obviously up to the platform to
take care of, and I think your API is a fairly good staging ground for
building up the layering in the platform parts.
Claiming that we set the pins once in the board setup code and then
forget about it is not realistic. I can't imagine anyone with many
different pin functions under mux (OMAP2 does too) seriously taking that
position.
So given that, I would argue that drivers _do_ care about the pins, just
not through the GPIO API.
On Mon, 20 Nov 2006 13:47:08 -0800
David Brownell <[email protected]> wrote:
> On Thursday 16 November 2006 6:54 am, Haavard Skinnemoen wrote:
> > I'm still not sure about how to implement the
> > gpio_request()/gpio_free() calls, though.
>
> Simplest would be to manipulate a bitmask:
>
> gpio_request() --> return test_and_set_bit(...) ? -EBUSY : 0;
> gpio_free() --> clear_bit(...)
Yeah, I'm fine with this part.
> Or if you want to track the identifiers and provide a debugfs dump
> of the active GPIOs and their status, use an array of strings (and
> spinlock its updates) or nuls as "fat bits", instead of a bit array.
Might be useful. Maybe we should add a "struct device" parameter to
gpio_request() as well, to allow platforms to associate pins with the
devices using them through sysfs? Or perhaps just to generate an
appropriate name (otherwise, each driver would have to generate a
unique string by themselves, for each device it controls.)
> > Since they're not supposed to
> > do any port configuration, I think I might convert them to no-ops
> > and do the allocation (and warn about conflicts) when configuring
> > the port multiplexer.
>
> What they're supposed to do is report conflicts between two
> drivers which both think they own the GPIO ... as errors.
>
> That's different from pin mux setup, which for most embedded
> systems is just making sure the SOC is configured to match
> what Linux expects. The boot loader usualy does some of that,
> but it's probably not validated to do more than reliably boot
> an operating system ... so pin muxing can't realistically
> report anything as an error. At best, it's a suggestion to
> update the bootloader someday.
I think I understand now. I have to use separate bitmasks for GPIO and
port mux setup.
If gpio_request() could do port mux configuration, one bitmask would be
enough to trap all errors. But after reading the rest of this thread,
I think separating the gpio and portmux APIs is a good idea, so I'm not
going to try to do this. Although I might set a bit in both masks when
configuring a pin for peripheral I/O, just to indicate that it isn't
usable for gpio at all.
> > Since the pin will be configured for one particular usage,
> > having multiple drivers try to use it will cause problems and
> > handing it out to the first driver that comes along will not really
> > solve anything...
>
> No, but letting the second one report the fatal error is a big help.
> And heck, you've got reasonable chance the first driver will work,
> if the second doesn't interfere with it! (Or maybe it's the other
> way around. At least you'd have logged a fatal error message ...)
You're right.
> > Of course, if other arches want gpio_request()/gpio_free(), I'm all
> > for keeping them.
>
> I thought you were someone who _wanted_ this mechanism?
> Or were you instead thinking of a pin mux mechanism?
Yes and yes ;)
Which is of course the source of all this confusion. I just had to
realize that the final definition of gpio_request was I little bit
different than I originally expected. This means that gpio_request() is
no longer _essential_ on avr32 (which corresponds nicely with its
classification as "optional" in your api proposal) but very nice to
have.
> > +int gpio_request(unsigned int gpio, const char *label)
> > +{
> > + struct pio_device *pio;
> > + unsigned int pin;
> > +
> > + pio = gpio_to_pio(gpio);
> > + if (!pio)
> > + return -ENODEV;
> > +
> > + pin = gpio & 0x1f;
> > + if (test_and_set_bit(pin, &pio->alloc_mask))
> > + return -EBUSY;
> > +
> > + pio_writel(pio, PER, 1 << pin);
>
> Enabling the pin as a GPIO is a pin mux responsibility, not
> a "keep drivers from stepping all over each other" thing.
Agreed. I'll change this.
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(gpio_request);
> > +
> > +void gpio_free(unsigned int gpio)
> > +{
> > + struct pio_device *pio;
> > + unsigned int pin;
> > +
> > + pio = gpio_to_pio(gpio);
> > + BUG_ON(!pio);
>
> Don't use BUG_ON in new code ... in this case it'd be best to just
> warn and return. Notice by the way that this isn't an inverse of
> the gpio_request(), since you aren't taking the pin back from the
> GPIO controller.
Ok, I'll drop the BUG_ON(). There's really no way to take the pin back
from the GPIO controller, as "gpio" is just one of three states where
the other two assigns the pin to a specific peripheral. Leaving the pin
configured for gpio seemed the best solution.
But I'm going to remove the port configuration stuff anyway, so it
doesn't matter.
> > +#define GPIO_PIOA_BASE (0)
> > +#define GPIO_PIN_PA0 (GPIO_PIOA_BASE + 0)
> > +#define GPIO_PIN_PA1 (GPIO_PIOA_BASE + 1)
> > +#define GPIO_PIN_PA2 (GPIO_PIOA_BASE + 2)
> > ...
>
> Someone had the suggestion to reduce the number of #defines
> by doing someting like
>
> #define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
> #define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
> #define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
> #define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
>
> I kind of like that, even if it's not such a direct match to
> Atmel's documentation.
I kind of like it too. It's a direct enough match for me.
> Aren't you going to want to add AVR-specific extensions so that
> drivers (or more typically, board init code) can manage pullups
> and input de-glitching?
Yeah, I will definitely do that, but I thought that was supposed to be
part of the portmux api?
Haavard
David Brownell wrote:
>On Monday 20 November 2006 9:09 pm, Bill Gatliff wrote:
>
>
>>Why not have GPIO numbers refer to unique combinations of GPIO+pin?
>>
>>
>
>That sounds unduly complicated compared to just using the GPIO numbers
>which are used throughout the hardware and software docs.
>
Yes, and no. On OMAP, they are indeed GPIO<m>-<n>. On XScale they're
GP<m>-<n>.
On AT91, they're P[ABCD][0-31]. On AVR32, they're P[ABCDE][0-31]. For
AU1500 (MIPS), they're GP[0-215], with a lot of holes--- there are only
48 lines actually available. On MPC885 (PowerPC), they're
P[ABCDE][random(0,31)].
Ok, I stretched the truth on that last one just a bit. :) Point is,
many machines don't have a concept of a "gpio number" except within the
context of a specific PIO controller. On OMAP, apparently all the PIOs
live in a unified space; on lots of other machines, they're organized
differently, e.g. four independent spaces (controllers), each of which
has 32 lines. The only consistent theme is that there's no consistent
theme.
I totally agree with you that the name assigned to GPIOs need to map as
closely as possible to the names used in datasheets. For OMAP, those
names can map one-to-one to integers. For AT91, something like this
might work better:
enum {PIOA0 = 0, PIOA1 = 1, ... PIOB0 = 32, PIOB1 = 1, ... PIOC0 =
64, PIOC1 = 65, ...};
So the "gpio number" in AT91 would, as it turns out, also encode the
line number in the lower 6 bits, and the controller number in the bits
above that.
Once you're hiding the GPIO number behind an enumeration, you can create
a bitmap with more information than a single integer. That extra
information could be used--- in my implementations, if any ever come
about--- to store routing information.
So on OMAP, the gpio numbers could be defined something like this:
#define MUX(n) ((n) << 24) /* Reg4 setting */
#define BANK(n) ((n) << 16) /* which GPIO register bank */
#define BIT(n) ((n) & 0xff) /* which bit in the above register
bank */
enum {... GPIO57M8 = (MUX(7) | BANK(2) | BIT(3)), GPIO57H19 =
(MUX(6) | BANK(2) | BIT(3)) ... };
(the above is mostly fiction, since I haven't fully grokk'ed the OMAP
datasheet and am hoping to avoid the need to).
I was just assuming that this was implied by the proposal--- or at least
it wasn't prohibited by it--- for machines that needed it.
And again, the fact that "GPIO57M8" would only be defined for OMAP
wouldn't be a problem--- you wouldn't be building a platform_struct for
a non-OMAP platform using the OMAP enumerations, anyway. And if somehow
you find that you are, a compiler error is probably the appropriate
response.
>It'd also be a big (and needless) disruption to code that's been working fine for several years now ...
>
... all of which is using the current GPIO API, you mean? :)
Perhaps yet another reason why the gpio_request function might want to
look at the hardware state--- so that drivers that aren't using the new
API are still known to the GPIO resource manager by virtue of the
signature they leave behind in the hardware configuration (you might not
be able to detect that they're using a GPIO line, but you would be able
to detect that a pin had been assigned to a non-GPIO function).
> and there'd need to be some scheme to recognize
>that most GPIO numbers suddenly become invalid (since the space would
>become large and sparsely populated, vs small and dense).
>
>
Not sure I understand you here, but if I do then I think this doesn't
matter. The drivers and platform_structs would be using the enumeration
symbols, not raw integers, so they don't interact directly with gpio
number space at all.
>Maybe if it were being done over from scratch, that'd be workable.
>But at this point I have a hard time seeing anyone want to change,
>even if there were a better argument.
>
>
Waitaminit. I thought this arch-neutral GPIO API *was* a from-scratch!
Did I miss something?
>Pin muxing is set up once, early, and from then on it suffices to use
>the GPIO number.
>
Now that I understand how you're using the term "muxing" a little
better, I think this statement oversimplifies things a bit.
>The mux problems are orthogonal to GPIOs.
>
>
Again, now that I understand your usage of the term, I'm not so sure
this is true anymore. :)
>Updating the GPIO controller is always (all architectures!) done in terms
>of a number mapping to some controller and a bit number, not a pin. The
>drivers never care about pins.
>
>
Only to the extent that the signals the driver is producing get to where
they're going. HOW that is established is indeed explicitly left out of
the driver itself, but it's awfully nice when there's a facility
somewhere that can do it on the driver's behalf.
There's a ton of code in the AT91 tree that sets up pin routing on
behalf of peripheral drivers like MMC, etc. MMC also uses GPIO. So
you're suggesting that we should take the pin routing a.k.a "muxing" out
of that driver? I think it's kind of nice when the driver can ask that
somebody, somewhere, assign the pins it needs to the peripheral
functions. Just one less headache for new authors.
And if that code exists somewhere, then it has to at least talk to the
GPIO resource manager so that the manager knows those pins are
off-limits as GPIO.
>The only thing that cares about pins is board setup code -- briefly.
>
>
So, once the board setup code has run then pin assignments don't
matter? I think that a more accurate statement is that as a driver
loads, it begins to care about pins. And it does so until it unloads,
at which point some other driver might care about them.
Arabella's PPC Linux kernels (which I'm working with at the moment) have
a resource manager not unlike what we're discussing here. It's very,
very heavy and unpleasant in spots, so I won't offer code or examples,
but it is pretty adept at getting pin routing right when a driver
initializes. And it can also prevent pin assignment conflicts--- which
have saved me in a few situations, and made debugging easier in others.
I don't like their implementation, but the functionality is much-needed.
None of what I'm suggesting affects the signatures of the functions
specified by your API at all. I'm just hiding more information behind
the notion of "gpio number", in a way that lets the implementors also
incorporate routing (both detection and assignment) into them.
b.g.
--
Bill Gatliff
[email protected]
On Monday 20 November 2006 10:09 pm, Paul Mundt wrote:
> On Mon, Nov 20, 2006 at 09:35:38PM -0800, David Brownell wrote:
> > On Monday 20 November 2006 9:09 pm, Bill Gatliff wrote:
> > > It seems like the point
> > > here is to help a driver find and assert their GPIO _pin_ so that the
> > > driver can can talk to the attached external hardware.
> >
> > Updating the GPIO controller is always (all architectures!) done in terms
> > of a number mapping to some controller and a bit number, not a pin. The
> > drivers never care about pins.
> >
> > The only thing that cares about pins is board setup code -- briefly.
> >
> That's rather simplifying things.
Not much. The only counterexample I know about just now is wanting
to use a UART.RX pin as a wakeup GPIO, even when the baud rate clock
is turned off during sleep ... only on development platforms.
> There is a need to layer a pin mux API underneath the GPIO API to deal
> with these sorts of things, but that's obviously up to the platform to
> take care of, and I think your API is a fairly good staging ground for
> building up the layering in the platform parts.
Not entirely "mine" ... except in the writeup of the abstraction that's
already in wide use (with different syntax).
If we can agree on syntax, and factoring pin mux separately (however it
gets implemented) I think the immediate goal is satisfied.
> Claiming that we set the pins once in the board setup code and then
> forget about it is not realistic. I can't imagine anyone with many
> different pin functions under mux (OMAP2 does too) seriously taking that
> position.
It's realistic in a couple dozen different systems I've seen, including
ones using OMAP2. Isn't that serious enough? :)
> So given that, I would argue that drivers _do_ care about the pins, just
> not through the GPIO API.
I'm not quite sure what you're getting at with that any more, but so long
as you agree that it makes sense to have a GPIO API with more or less the
syntax I collected, distinct from pin mux/setup/reconfig, we're in close
enough agreement to move forward to whatever.
I know some folk say they "need" to remux after boot in non-exceptional cases,
but the ability to do that (or not) really seems like a separate discussion.
- Dave
On Tuesday 21 November 2006 1:11 am, Haavard Skinnemoen wrote:
> > Or if you want to track the identifiers and provide a debugfs dump
> > of the active GPIOs and their status, use an array of strings (and
> > spinlock its updates) or nuls as "fat bits", instead of a bit array.
>
> Might be useful. Maybe we should add a "struct device" parameter to
> gpio_request() as well, to allow platforms to associate pins with the
> devices using them through sysfs? Or perhaps just to generate an
> appropriate name (otherwise, each driver would have to generate a
> unique string by themselves, for each device it controls.)
I'm not so keeen on putting sysfs everywhere; it's not free!
The notion of passing a device node makes some sense, except
that a lot of the places I'm used to seeing GPIO requests are
so early in the boot code that there _is_ no device node yet.
Let me think about that one a bit...
> I think I understand now. I have to use separate bitmasks for GPIO and
> port mux setup.
>
> If gpio_request() could do port mux configuration, one bitmask would be
> enough to trap all errors. But after reading the rest of this thread,
> I think separating the gpio and portmux APIs is a good idea, so I'm not
> going to try to do this. Although I might set a bit in both masks when
> configuring a pin for peripheral I/O, just to indicate that it isn't
> usable for gpio at all.
On your hardware, you could just read the hardware when setting
the gpio direction ... don't need an extra mask to catch that
class of error.
> > > Of course, if other arches want gpio_request()/gpio_free(), I'm all
> > > for keeping them.
> >
> > I thought you were someone who _wanted_ this mechanism?
> > Or were you instead thinking of a pin mux mechanism?
>
> Yes and yes ;)
>
> Which is of course the source of all this confusion. I just had to
> realize that the final definition of gpio_request was I little bit
> different than I originally expected. This means that gpio_request() is
> no longer _essential_ on avr32 (which corresponds nicely with its
> classification as "optional" in your api proposal) but very nice to
> have.
Right; I think I've had the OMAP analogue of gpio_request() turn
up errors only once (that code base was once a lot dirtier), but
some newish debug dump code worked a lot better with that.
> > Aren't you going to want to add AVR-specific extensions so that
> > drivers (or more typically, board init code) can manage pullups
> > and input de-glitching?
>
> Yeah, I will definitely do that, but I thought that was supposed to be
> part of the portmux api?
Yes it is. I suppose I shouldn't have assumed it would go into
that gpio.h header file, even though that's where it started out
on the at91 platform. :)
- Dave
On Monday 20 November 2006 9:51 pm, Bill Gatliff wrote:
> In OMAP, as far as I can tell after skimming the datasheet (and being
> reminded why I avoid TI's microcontrollers!),
Microcontroller?? Hah! That'd be MSP430, or AVR8, or an ARM7 ... when
it can run vmlinux, it seems far away from being a microcontroller!
Despite how long it can run on a teeny weeny battery.
You'd like OMAP2 better though, in terms of pin setup it's way nicer.
Each GPIO seems to correspond to a single pin. Nobody much liked the
consequences of how OMAP1 did it.
> someone has to set up the
> MUX so that a given GPIO can get to a specified pin. And practically
> speaking, what's soldered to a pin is nearly immutable for a given board
> (or at least a particular revision; you won't change it in software
> anyway!).
Yep; though there _is_ the model of "SOC-on-a-card" plugging into a
custom chassis (maybe an industrial app), as opposed to using custom
boards for everything. Though if you think of the "board" as being
that whole chassis-plus-CPUcard assembly, it's still more or less
immutable as you described.
> So for sanity's sake the GPIO "resource manager" would have
> to refuse a request for a GPIO line assigned to a pin that had already
> been committed to something else, be it another GPIO line or a
> peripheral function. So I think having the notion of a resource manager
> _at all_ implies that you're into some amount of MUX analysis/management
> on machines that have them.
That's a big "if". There's no such "manager" right now, other than the
people designing a given board and putting Linux onto it.
> Aside: You state that there are many-to-many possibilities. In theory
> yes, but for OMAP and any other practical machine, no. You never have
> an infinite number of pins or GPIOs, so even with some kind of radical
> "switch fabric" the number of unique combinations of GPIO+pin still
> would be bounded. In the case of OMAP, it looks like most of the GPIOs
> can be assigned to one of two pins, and each pin can be assigned to one
> of two GPIOs. So, "some-to-some". :)
My point was more that it's "not one-to-one". And clearly a given system
will only use one mapping (Paul's comments aside) ... the issue is that
knowing you're using a particular GPIO doesn't mean you know what pin is
involved, and contrariwise that knowing what pin doesn't mean you know what
GPIO to use.
Yes it's a PITA ... and I've seen boards that needed to get re-spun because
the board desigersn goofed, with two different interfaces expecting to mux a
(different) pin to GPIO7. Didn't get discovered till late since each of the
two interfaces worked fine by themselves; system integration testing found it.
I suspect that's one reason OMAP2 is different in how it does the pin setup!
> The "multiplexing" that I was wishing to leave out of the GPIO API was
> the part where you assign pins to peripheral functions *or* GPIO, a'la
> AT91. The existing kernel code for that chip provides a number of
> functions to help board authors get all the routing and configuration
> right for each pin ("peripheral A function, or peripheral B, or GPIO?
> Input, or output? Pullup resistor, or no? Input filtering, or no?")
> (*). I'm ok with not trying to consolidate that functionality in an
> arch-neutral GPIO-only API right now, since machines do that so differently.
Yes, I think we're seeing agreement on that now.
> But I was assuming all along that we were overloading the notion of a
> "gpio number" enumeration, such that each enumeration ultimately
> referred to a unique combination of GPIO+pin for the instant machine.
Well, none of the existing software does that, or has needed to.
To the extent that the $SUBJECT calls are just common syntax for
what many platforms are already doing, they all use the same notion
of a "gpio number" which doesn't reference pinout ... there's a
direct mapping to a bit in a gpio controller register, that's it.
> And once you've got that, there's no reason why the underlying
> implementation couldn't assert the proper routing at the time a specific
> GPIO+pin was requested. Maybe that's up to the individual authors as to
> whether they want to provide this in their implementations, or choose
> instead to leave out the MUX configuration and just map GPIO
> enumerations to physical GPIO line numbers (and hope for the best at
> runtime). But I still don't see a reason why they shouldn't if they're
> willing to do the code.
They could; the GPIO numbers, and interpretation, are platform-specific.
> Sorry to recycle on all of this again. Maybe I'm just a slow learner,
> maybe I just was misunderstanding some of the terminology we were
> throwing around. Maybe it's something else entirely.
Who knows. I thought you were most likely wishing everything was as
simple and straightforward as it is on AT91, AVR32, and OMAP2. ;)
In the restricted context of GPIO numbers, I think it is. And it might
even be practical to come up with a widely used pin mux API ... it's
just that significant platforms like OMAP1 would be unlikely to fit.
- Dave
>
>
> * - Most of which was written by Dave Brownell. Thanks!
>
>
>
> b.g.
>
> --
> Bill Gatliff
> [email protected]
>
David:
David Brownell wrote:
>I know some folk say they "need" to remux after boot in non-exceptional cases,
>but the ability to do that (or not) really seems like a separate discussion.
>
>
I don't need to REmux, but I don't want to bother setting up the routing
manually at all. I think the GPIO management stuff can do it properly
on my behalf, given the information we have to acquire to get the GPIO
API to work in the first place.
Kind of like with request_irq() and enable_irq(). The driver is saying,
"I don't care what's actually behind this interrupt source X, I just
want it routed over to me". If we commit to hiding the muxing behind
the API, instead of defining a new, parallel API, we get that kind of
mentality for GPIO as well.
That's all. Go forth and code. :)
b.g.
--
Bill Gatliff
[email protected]
On Tue, Nov 21, 2006 at 09:36:17PM -0600, Bill Gatliff wrote:
> David Brownell wrote:
> >I know some folk say they "need" to remux after boot in
> >non-exceptional cases, but the ability to do that (or not) really
> >seems like a separate discussion.
>
> I don't need to REmux, but I don't want to bother setting up the routing
> manually at all. I think the GPIO management stuff can do it properly
> on my behalf, given the information we have to acquire to get the GPIO
> API to work in the first place.
>
You can't really have one without the other, and if you're going to add
that sort of functionality, it's not strictly tied to the GPIOs.
> Kind of like with request_irq() and enable_irq(). The driver is saying,
> "I don't care what's actually behind this interrupt source X, I just
> want it routed over to me". If we commit to hiding the muxing behind
> the API, instead of defining a new, parallel API, we get that kind of
> mentality for GPIO as well.
>
As soon as a driver comes along and says that it wants, say, GPIO 42,
which happens to be an alternate pin function for pin #128, you've
effectively coupled the two, especially since the underlying refcounting
is more applicable to the pin function than the GPIO itself.
And this is something where you will have to remux, or at least force
that GPIOs availability through the board setup code, but there's little
point in dealing with mux issues in the board setup code at all if this
is done dynamically based off of the driver requirements and subsequent
refcounting.
Static muxing is something that no longer makes any sense. Devices are
piling more and more desired functions under mux, and that's not going
away.
On Tuesday 21 November 2006 7:36 pm, Bill Gatliff wrote:
> I don't need to REmux, but I don't want to bother setting up the routing
> manually at all. I think the GPIO management stuff can do it properly
> on my behalf, given the information we have to acquire to get the GPIO
> API to work in the first place.
Yet requesting GPIO_62 still doesn't tell me I have to
update muxing for ball M7 or G20 ... and knowing that for
GPIOs doesn't go anywhere near knowing that for all the
other chip functions.
David:
David Brownell wrote:
>On Tuesday 21 November 2006 7:36 pm, Bill Gatliff wrote:
>
>
>
>>I don't need to REmux, but I don't want to bother setting up the routing
>>manually at all. I think the GPIO management stuff can do it properly
>>on my behalf, given the information we have to acquire to get the GPIO
>>API to work in the first place.
>>
>>
>
>Yet requesting GPIO_62 still doesn't tell me I have to
>update muxing for ball M7 or G20
>
Which is why I was pushing you to define a GPIO62M7 enumeration!
> ... and knowing that for
>GPIOs doesn't go anywhere near knowing that for all the
>other chip functions.
>
>
True, but we've got to start somewhere! :)
b.g.
--
Bill Gatliff
[email protected]
On Tuesday 21 November 2006 7:57 am, Bill Gatliff wrote:
> Once you're hiding the GPIO number behind an enumeration, you can create
> a bitmap with more information than a single integer. That extra
> information could be used--- in my implementations, if any ever come
> about--- to store routing information.
But none of the existing GPIO users do that. The goal wasn't to define
a new notion of GPIO; it was collecting the existing ones under a single
arch-neutral umbrella.
> >It'd also be a big (and needless) disruption to code that's been working
> >fine for several years now ...
>
> ... all of which is using the current GPIO API, you mean? :)
Effectively, yes. I counted quite a few implementations in the current
tree which can trivially (#defines) map to that API.
> >Maybe if it were being done over from scratch, that'd be workable.
> >But at this point I have a hard time seeing anyone want to change,
> >even if there were a better argument.
>
> Waitaminit. I thought this arch-neutral GPIO API *was* a from-scratch!
> Did I miss something?
The numerous implementations, e.g. on ARM, that effectively are
already using this same API, I'd guess. The ones that uniformly
reference GPIOs by an integer.
> There's a ton of code in the AT91 tree that sets up pin routing on
> behalf of peripheral drivers like MMC, etc. MMC also uses GPIO.
I just checked RC6, and see that at91_mmc doesn't set up routing.
Which is as it should be ... routing is part of board setup, saying
"these pins go to the MMC card". Pretty much the same with all
other peripherals. They do have calls to read GPIO values, or in
some cases set them. But ** NOT ** to route them.
> Arabella's PPC Linux kernels (which I'm working with at the moment) have
> a resource manager not unlike what we're discussing here.
Well, like _you_ are discussing. I'm mostly pointing out that
pin muxing and configuration is a clearly distinct problem,
with very chip-specific nuances.
> It's very,
> very heavy and unpleasant in spots, so I won't offer code or examples,
> but it is pretty adept at getting pin routing right when a driver
> initializes. And it can also prevent pin assignment conflicts--- which
> have saved me in a few situations, and made debugging easier in others.
> I don't like their implementation, but the functionality is much-needed.
Most highly integrated chips nowadays need such functionality. If you're
keen on it, you could try to abstract a dozen pin mux/setup implementations
and propose an API ... in the same way I did for GPIOs. :)
> None of what I'm suggesting affects the signatures of the functions
> specified by your API at all. I'm just hiding more information behind
> the notion of "gpio number", in a way that lets the implementors also
> incorporate routing (both detection and assignment) into them.
And as I've defined those numbers, that's certainly allowed. But not
required. I'm just pushing back on the notion that it be required,
since adding such heavy requirements would prevent quick API support
for GPIOs.
- Dave
Here's another go at an implementation of the arch-neutral GPIO API for
AVR32. I've also thrown in the pin configuration stuff so that you can
see how all the pieces fit together.
Even though it is possible to tell from the hardware whether a pin is
set up for GPIO, I decided to use two allocation bitmasks per pio
controller to keep track of what the pins are used for: pinmux_mask and
gpio_mask.
pinmux_mask indicates which pins have been configured for usage either
by a peripheral or GPIO. If the corresponding bit is set when trying to
configure a pin, a warning will be printed along with a stack dump (no
BUG anymore.)
gpio_mask indicates which pins are available for GPIO. It starts out as
all ones, and whenever a pin is configured for GPIO, the corresponding
bit is cleared. gpio_request() test_and_set()s a bit in the mask
corresponding to the pin being requested, and if it's already set
(either because it hasn't been configured or because it's been
requested by a different driver), gpio_request() returns an error value.
The pin configuration API is AVR32-specific for now.
Signed-off-by: Haavard Skinnemoen <[email protected]>
---
arch/avr32/mach-at32ap/at32ap7000.c | 144 ++++++++++-----------
arch/avr32/mach-at32ap/pio.c | 186 ++++++++++++++++++++++++++--
include/asm-avr32/arch-at32ap/at32ap7000.h | 26 ++++
include/asm-avr32/arch-at32ap/gpio.h | 39 ++++++
include/asm-avr32/arch-at32ap/irq.h | 11 ++
include/asm-avr32/arch-at32ap/portmux.h | 16 ---
include/asm-avr32/gpio.h | 6 +
include/asm-avr32/irq.h | 8 +-
8 files changed, 333 insertions(+), 103 deletions(-)
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 7ff6ad8..c80385d 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -11,8 +11,9 @@
#include <asm/io.h>
+#include <asm/arch/at32ap7000.h>
#include <asm/arch/board.h>
-#include <asm/arch/portmux.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/sm.h>
#include "clock.h"
@@ -67,17 +68,8 @@ static struct clk devname##_##_name = {
.index = _index, \
}
-enum {
- PIOA,
- PIOB,
- PIOC,
- PIOD,
-};
-
-enum {
- FUNC_A,
- FUNC_B,
-};
+#define select_peripheral(pin, periph, pullup) \
+ at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, pullup)
unsigned long at32ap7000_osc_rates[3] = {
[0] = 32768,
@@ -569,26 +561,26 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
static inline void configure_usart0_pins(void)
{
- portmux_set_func(PIOA, 8, FUNC_B); /* RXD */
- portmux_set_func(PIOA, 9, FUNC_B); /* TXD */
+ select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
+ select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
}
static inline void configure_usart1_pins(void)
{
- portmux_set_func(PIOA, 17, FUNC_A); /* RXD */
- portmux_set_func(PIOA, 18, FUNC_A); /* TXD */
+ select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
+ select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
}
static inline void configure_usart2_pins(void)
{
- portmux_set_func(PIOB, 26, FUNC_B); /* RXD */
- portmux_set_func(PIOB, 27, FUNC_B); /* TXD */
+ select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
+ select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
}
static inline void configure_usart3_pins(void)
{
- portmux_set_func(PIOB, 18, FUNC_B); /* RXD */
- portmux_set_func(PIOB, 17, FUNC_B); /* TXD */
+ select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
+ select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
}
static struct platform_device *at32_usarts[4];
@@ -663,27 +655,27 @@ at32_add_device_eth(unsigned int id, str
case 0:
pdev = &macb0_device;
- portmux_set_func(PIOC, 3, FUNC_A); /* TXD0 */
- portmux_set_func(PIOC, 4, FUNC_A); /* TXD1 */
- portmux_set_func(PIOC, 7, FUNC_A); /* TXEN */
- portmux_set_func(PIOC, 8, FUNC_A); /* TXCK */
- portmux_set_func(PIOC, 9, FUNC_A); /* RXD0 */
- portmux_set_func(PIOC, 10, FUNC_A); /* RXD1 */
- portmux_set_func(PIOC, 13, FUNC_A); /* RXER */
- portmux_set_func(PIOC, 15, FUNC_A); /* RXDV */
- portmux_set_func(PIOC, 16, FUNC_A); /* MDC */
- portmux_set_func(PIOC, 17, FUNC_A); /* MDIO */
+ select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
+ select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
+ select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
+ select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
+ select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
+ select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
+ select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
+ select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
+ select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
+ select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
if (!data->is_rmii) {
- portmux_set_func(PIOC, 0, FUNC_A); /* COL */
- portmux_set_func(PIOC, 1, FUNC_A); /* CRS */
- portmux_set_func(PIOC, 2, FUNC_A); /* TXER */
- portmux_set_func(PIOC, 5, FUNC_A); /* TXD2 */
- portmux_set_func(PIOC, 6, FUNC_A); /* TXD3 */
- portmux_set_func(PIOC, 11, FUNC_A); /* RXD2 */
- portmux_set_func(PIOC, 12, FUNC_A); /* RXD3 */
- portmux_set_func(PIOC, 14, FUNC_A); /* RXCK */
- portmux_set_func(PIOC, 18, FUNC_A); /* SPD */
+ select_peripheral(PC(0), PERIPH_A, 0); /* COL */
+ select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
+ select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
+ select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
+ select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
+ select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
+ select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
+ select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
+ select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
}
break;
@@ -714,12 +706,12 @@ struct platform_device *__init at32_add_
switch (id) {
case 0:
pdev = &spi0_device;
- portmux_set_func(PIOA, 0, FUNC_A); /* MISO */
- portmux_set_func(PIOA, 1, FUNC_A); /* MOSI */
- portmux_set_func(PIOA, 2, FUNC_A); /* SCK */
- portmux_set_func(PIOA, 3, FUNC_A); /* NPCS0 */
- portmux_set_func(PIOA, 4, FUNC_A); /* NPCS1 */
- portmux_set_func(PIOA, 5, FUNC_A); /* NPCS2 */
+ select_peripheral(PA(0), PERIPH_A, 0); /* MISO */
+ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
+ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
+ select_peripheral(PA(3), PERIPH_A, 0); /* NPCS0 */
+ select_peripheral(PA(4), PERIPH_A, 0); /* NPCS1 */
+ select_peripheral(PA(5), PERIPH_A, 0); /* NPCS2 */
break;
default:
@@ -762,37 +754,37 @@ at32_add_device_lcdc(unsigned int id, st
switch (id) {
case 0:
pdev = &lcdc0_device;
- portmux_set_func(PIOC, 19, FUNC_A); /* CC */
- portmux_set_func(PIOC, 20, FUNC_A); /* HSYNC */
- portmux_set_func(PIOC, 21, FUNC_A); /* PCLK */
- portmux_set_func(PIOC, 22, FUNC_A); /* VSYNC */
- portmux_set_func(PIOC, 23, FUNC_A); /* DVAL */
- portmux_set_func(PIOC, 24, FUNC_A); /* MODE */
- portmux_set_func(PIOC, 25, FUNC_A); /* PWR */
- portmux_set_func(PIOC, 26, FUNC_A); /* DATA0 */
- portmux_set_func(PIOC, 27, FUNC_A); /* DATA1 */
- portmux_set_func(PIOC, 28, FUNC_A); /* DATA2 */
- portmux_set_func(PIOC, 29, FUNC_A); /* DATA3 */
- portmux_set_func(PIOC, 30, FUNC_A); /* DATA4 */
- portmux_set_func(PIOC, 31, FUNC_A); /* DATA5 */
- portmux_set_func(PIOD, 0, FUNC_A); /* DATA6 */
- portmux_set_func(PIOD, 1, FUNC_A); /* DATA7 */
- portmux_set_func(PIOD, 2, FUNC_A); /* DATA8 */
- portmux_set_func(PIOD, 3, FUNC_A); /* DATA9 */
- portmux_set_func(PIOD, 4, FUNC_A); /* DATA10 */
- portmux_set_func(PIOD, 5, FUNC_A); /* DATA11 */
- portmux_set_func(PIOD, 6, FUNC_A); /* DATA12 */
- portmux_set_func(PIOD, 7, FUNC_A); /* DATA13 */
- portmux_set_func(PIOD, 8, FUNC_A); /* DATA14 */
- portmux_set_func(PIOD, 9, FUNC_A); /* DATA15 */
- portmux_set_func(PIOD, 10, FUNC_A); /* DATA16 */
- portmux_set_func(PIOD, 11, FUNC_A); /* DATA17 */
- portmux_set_func(PIOD, 12, FUNC_A); /* DATA18 */
- portmux_set_func(PIOD, 13, FUNC_A); /* DATA19 */
- portmux_set_func(PIOD, 14, FUNC_A); /* DATA20 */
- portmux_set_func(PIOD, 15, FUNC_A); /* DATA21 */
- portmux_set_func(PIOD, 16, FUNC_A); /* DATA22 */
- portmux_set_func(PIOD, 17, FUNC_A); /* DATA23 */
+ select_peripheral(PC(19), PERIPH_A, 0); /* CC */
+ select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
+ select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
+ select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
+ select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
+ select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
+ select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
+ select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
+ select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
+ select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
+ select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
+ select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
+ select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
+ select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
+ select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
+ select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
+ select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
+ select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
+ select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
+ select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
+ select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
+ select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
+ select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
+ select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+ select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+ select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+ select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+ select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+ select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+ select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+ select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
clk_set_parent(&lcdc0_pixclk, &pll0);
clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index d3aabfc..92e151d 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -13,10 +13,9 @@
#include <linux/fs.h>
#include <linux/platform_device.h>
+#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/arch/portmux.h>
-
#include "pio.h"
#define MAX_NR_PIO_DEVICES 8
@@ -25,28 +24,191 @@ struct pio_device {
void __iomem *regs;
const struct platform_device *pdev;
struct clk *clk;
- u32 alloc_mask;
+ u32 pinmux_mask;
+ u32 gpio_mask;
char name[32];
};
static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
- unsigned int function_id)
+static struct pio_device *gpio_to_pio(unsigned int gpio)
{
struct pio_device *pio;
- u32 mask = 1 << pin_id;
+ unsigned int index;
+
+ index = gpio >> 5;
+ if (index >= MAX_NR_PIO_DEVICES)
+ return NULL;
+ pio = &pio_dev[index];
+ if (!pio->regs)
+ return NULL;
+
+ return pio;
+}
+
+/* Pin multiplexing API */
- BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES);
+void __init at32_select_periph(unsigned int pin, unsigned int periph,
+ int use_pullup)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+ u32 mask = 1 << pin_index;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ goto fail;
+ }
- pio = &pio_dev[portmux_id];
+ if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+ printk("%s: pin %u is busy\n", pio->name, pin_index);
+ goto fail;
+ }
- if (function_id)
+ pio_writel(pio, PUER, mask);
+ if (periph)
pio_writel(pio, BSR, mask);
else
pio_writel(pio, ASR, mask);
+
pio_writel(pio, PDR, mask);
+ if (!use_pullup)
+ pio_writel(pio, PUDR, mask);
+
+ return;
+
+fail:
+ dump_stack();
+}
+
+void __init at32_select_gpio(unsigned int pin, int enable_output,
+ int use_pullup)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+ u32 mask = 1 << pin_index;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ goto fail;
+ }
+
+ if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+ printk("%s: pin %u is busy\n", pio->name, pin_index);
+ goto fail;
+ }
+
+ pio_writel(pio, PUER, mask);
+ if (enable_output)
+ pio_writel(pio, OER, mask);
+ else
+ pio_writel(pio, ODR, mask);
+
+ pio_writel(pio, PER, mask);
+ if (!use_pullup)
+ pio_writel(pio, PUDR, mask);
+
+ /* It's now allowed to use request_gpio on this pin */
+ clear_bit(pin_index, &pio->gpio_mask);
+
+ return;
+
+fail:
+ dump_stack();
+}
+
+/* GPIO API */
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ if (test_and_set_bit(pin, &pio->gpio_mask))
+ return -EBUSY;
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio) {
+ printk(KERN_ERR
+ "gpio: attempted to free invalid pin %u\n", gpio);
+ return;
+ }
+
+ pin = gpio & 0x1f;
+ if (!test_and_clear_bit(pin, &pio->gpio_mask))
+ printk(KERN_ERR "gpio: freeing already-free pin %s[%u]\n",
+ pio->name, pin);
}
+EXPORT_SYMBOL(gpio_free);
+
+int gpio_direction_input(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ pio_writel(pio, ODR, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned int gpio)
+{
+ struct pio_device *pio;
+ unsigned int pin;
+
+ pio = gpio_to_pio(gpio);
+ if (!pio)
+ return -ENODEV;
+
+ pin = gpio & 0x1f;
+ pio_writel(pio, OER, 1 << pin);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned int gpio)
+{
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+
+ return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned int gpio, int value)
+{
+ struct pio_device *pio = &pio_dev[gpio >> 5];
+ u32 mask;
+
+ mask = 1 << (gpio & 0x1f);
+ if (value)
+ pio_writel(pio, SODR, mask);
+ else
+ pio_writel(pio, CODR, mask);
+}
+EXPORT_SYMBOL(gpio_set_value);
static int __init pio_probe(struct platform_device *pdev)
{
@@ -113,6 +275,12 @@ void __init at32_init_pio(struct platfor
pio->pdev = pdev;
pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ /*
+ * request_gpio() is only valid for pins that have been
+ * configured as GPIO.
+ */
+ pio->gpio_mask = ~0UL;
+
pio_writel(pio, ODR, ~0UL);
pio_writel(pio, PER, ~0UL);
}
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
new file mode 100644
index 0000000..8bdedbc
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/at32ap7000.h
@@ -0,0 +1,26 @@
+#ifndef __ASM_ARCH_AT32AP7000_H
+#define __ASM_ARCH_AT32AP7000_H
+
+#define GPIO_PERIPH_A 0
+#define GPIO_PERIPH_B 1
+
+#define NR_GPIO_CONTROLLERS 4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be converted to IRQ numbers by passing them through
+ * gpio_to_irq().
+ */
+#define GPIO_PIOA_BASE (0)
+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
+#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32)
+
+#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
+#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
+#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
+#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
+#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N))
+
+#endif /* __ASM_ARCH_AT32AP7000_H */
diff --git a/include/asm-avr32/arch-at32ap/gpio.h b/include/asm-avr32/arch-at32ap/gpio.h
new file mode 100644
index 0000000..825582f
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/gpio.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <linux/compiler.h>
+#include <asm/irq.h>
+
+/*
+ * Set up pin multiplexing, called from board init only.
+ *
+ * The following flags determine the initial state of the pin.
+ */
+#define AT32_GPIOF_PULLUP 0x00000001 /* Enable pull-up */
+#define AT32_GPIOF_OUTPUT 0x00000002 /* Enable output driver */
+#define AT32_GPIOF_HIGH 0x00000004 /* Set output high */
+
+void at32_select_periph(unsigned int pin, unsigned int periph,
+ unsigned long flags);
+void at32_select_gpio(unsigned int pin, unsigned long flags);
+
+/* Arch-neutral GPIO API */
+int __must_check gpio_request(unsigned int gpio, const char *label);
+void gpio_free(unsigned int gpio);
+
+int gpio_direction_input(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio);
+int gpio_get_value(unsigned int gpio);
+void gpio_set_value(unsigned int gpio, int value);
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return gpio + GPIO_IRQ_BASE;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return irq - GPIO_IRQ_BASE;
+}
+
+#endif /* __ASM_AVR32_GPIO_H */
diff --git a/include/asm-avr32/arch-at32ap/irq.h b/include/asm-avr32/arch-at32ap/irq.h
new file mode 100644
index 0000000..1e2513e
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/irq.h
@@ -0,0 +1,11 @@
+#ifndef __ASM_AVR32_ARCH_IRQ_H
+#define __ASM_AVR32_ARCH_IRQ_H
+
+#define EIM_IRQ_BASE NR_INTERNAL_IRQS
+#define NR_EIM_IRQS 32
+#define GPIO_IRQ_BASE (EIM_IRQ_BASE + NR_EIM_IRQS)
+#define NR_GPIO_IRQS (4 * 32)
+
+#define NR_IRQS (GPIO_IRQ_BASE + NR_GPIO_IRQS)
+
+#endif /* __ASM_AVR32_ARCH_IRQ_H */
diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h
deleted file mode 100644
index 4d50421..0000000
--- a/include/asm-avr32/arch-at32ap/portmux.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * AT32 portmux interface.
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_AVR32_AT32_PORTMUX_H__
-#define __ASM_AVR32_AT32_PORTMUX_H__
-
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
- unsigned int function_id);
-
-#endif /* __ASM_AVR32_AT32_PORTMUX_H__ */
diff --git a/include/asm-avr32/gpio.h b/include/asm-avr32/gpio.h
new file mode 100644
index 0000000..19e8ccc
--- /dev/null
+++ b/include/asm-avr32/gpio.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <asm/arch/gpio.h>
+
+#endif /* __ASM_AVR32_GPIO_H */
diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
index f7e7257..83e6549 100644
--- a/include/asm-avr32/irq.h
+++ b/include/asm-avr32/irq.h
@@ -2,8 +2,12 @@
#define __ASM_AVR32_IRQ_H
#define NR_INTERNAL_IRQS 64
-#define NR_EXTERNAL_IRQS 64
-#define NR_IRQS (NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS)
+
+#include <asm/arch/irq.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS (NR_INTERNAL_IRQS)
+#endif
#define irq_canonicalize(i) (i)
--
1.4.3.3
Hi,
On 11/23/06, David Brownell <[email protected]> wrote:
> On Tuesday 21 November 2006 7:57 am, Bill Gatliff wrote:
>
> > Once you're hiding the GPIO number behind an enumeration, you can create
> > a bitmap with more information than a single integer. That extra
> > information could be used--- in my implementations, if any ever come
> > about--- to store routing information.
>
> But none of the existing GPIO users do that. The goal wasn't to define
> a new notion of GPIO; it was collecting the existing ones under a single
> arch-neutral umbrella.
>
>
> > >It'd also be a big (and needless) disruption to code that's been working
> > >fine for several years now ...
> >
> > ... all of which is using the current GPIO API, you mean? :)
>
> Effectively, yes. I counted quite a few implementations in the current
> tree which can trivially (#defines) map to that API.
I tried to do that for pxa, the patch is attached.
So what is the state of this discussion, now that 2.6.19 is here?
I just submitted an input driver for GPIO buttons to linux-input that
we use in the handhelds.org kernel for sa1100, pxa and s3c2410 archs.
It needs some ugly
#ifdefs currently, but with common GPIO calls they all could go away.
regards
Philipp
On 11/30/06, pHilipp Zabel <[email protected]> wrote:
> > Effectively, yes. I counted quite a few implementations in the current
> > tree which can trivially (#defines) map to that API.
Or so I thought, sorry.
regards
Philipp
On Tuesday 28 November 2006 4:36 am, Haavard Skinnemoen wrote:
> Here's another go at an implementation of the arch-neutral GPIO API for
> AVR32. I've also thrown in the pin configuration stuff so that you can
> see how all the pieces fit together.
That looks good, but it was probably better in a "portmux.h" header.
(Although the at32_* prefixes help a lot!) You don't use the flags
AT32_GPIO_PULLUP etc, either.
Other than that pinmux confusion, this looks pretty much OK to me.
The GPIO stuff matches the proposal.
> Even though it is possible to tell from the hardware whether a pin is
> set up for GPIO, I decided to use two allocation bitmasks per pio
> controller to keep track of what the pins are used for: pinmux_mask and
> gpio_mask.
>
> pinmux_mask indicates which pins have been configured for usage either
> by a peripheral or GPIO. If the corresponding bit is set when trying to
> configure a pin, a warning will be printed along with a stack dump (no
> BUG anymore.)
That is, pins without that set are still configured how the bootloader
left them ... possibly as they were left by system reset. On some systems
it might be desirable to warn when the mode Linux wants isn't what the
bootloader left, so that all the muxing code can be left out of Linux.
(Not that it can save much on AT91 or AVR32, but the bootloader was probably
writing those registers anyway, and saving codespace and boot time tends
to be a Good Thing.) Or so that Linux can't, oh, change the state of
the GPIO that keeps the saw switched off. ;)
I notice you didn't have a way to return pins to an "unclaimed" state
though, which would probably be disadvantageous in some cases. I don't
agree with the arguments made by Paul Mundt that such usage would be a
common thing ... but on the other hand, I bet you'd get complaints from
various folk if you make re-muxing excessively painful.
> gpio_mask indicates which pins are available for GPIO. It starts out as
> all ones, and whenever a pin is configured for GPIO, the corresponding
> bit is cleared. gpio_request() test_and_set()s a bit in the mask
> corresponding to the pin being requested, and if it's already set
> (either because it hasn't been configured or because it's been
> requested by a different driver), gpio_request() returns an error value.
Sounds OK. You are thus _requiring_ the pin muxing to have been
done before the gpio pin is requested ... sort of complicates the
"Linux uses bootloader's pin muxing" model.
> The pin configuration API is AVR32-specific for now.
>
> Signed-off-by: Haavard Skinnemoen <[email protected]>
> ---
> arch/avr32/mach-at32ap/at32ap7000.c | 144 ++++++++++-----------
> arch/avr32/mach-at32ap/pio.c | 186 ++++++++++++++++++++++++++--
> include/asm-avr32/arch-at32ap/at32ap7000.h | 26 ++++
> include/asm-avr32/arch-at32ap/gpio.h | 39 ++++++
> include/asm-avr32/arch-at32ap/irq.h | 11 ++
> include/asm-avr32/arch-at32ap/portmux.h | 16 ---
> include/asm-avr32/gpio.h | 6 +
> include/asm-avr32/irq.h | 8 +-
> 8 files changed, 333 insertions(+), 103 deletions(-)
>
> @@ -569,26 +561,26 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
>
> static inline void configure_usart0_pins(void)
> {
> - portmux_set_func(PIOA, 8, FUNC_B); /* RXD */
> - portmux_set_func(PIOA, 9, FUNC_B); /* TXD */
> + select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
> + select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
A constant like PULLUP_OFF would be clearer in these cases.
> +void __init at32_select_periph(unsigned int pin, unsigned int periph,
> + int use_pullup)
Declared as "flags" elsewhere, not "use_pullup"...
> +void __init at32_select_gpio(unsigned int pin, int enable_output,
> + int use_pullup)
> +/*
> + * Set up pin multiplexing, called from board init only.
> + *
> + * The following flags determine the initial state of the pin.
> + */
> +#define AT32_GPIOF_PULLUP 0x00000001 /* Enable pull-up */
> +#define AT32_GPIOF_OUTPUT 0x00000002 /* Enable output driver */
> +#define AT32_GPIOF_HIGH 0x00000004 /* Set output high */
> +
> +void at32_select_periph(unsigned int pin, unsigned int periph,
> + unsigned long flags);
> +void at32_select_gpio(unsigned int pin, unsigned long flags);
On Wednesday 29 November 2006 10:57 pm, pHilipp Zabel wrote:
> >
> > Effectively, yes. I counted quite a few implementations in the current
> > tree which can trivially (#defines) map to that API.
>
> I tried to do that for pxa, the patch is attached.
At a quick glance, that looked correct. However:
> +#define gpio_get_value(gpio)???(GPLR(gpio) & GPIO_bit(gpio))
> +#define gpio_set_value(gpio,value) \
> +???????((value)? (GPSR(gpio) = GPIO_bit(gpio)):(GPCR(gpio) = GPIO_bit(gpio)))
Given how much code those macros expand to, I'd consider making those calls
become inlines which check whether "gpio" is a constant or not.
if gpio (and value to set?) is a constant
then use that inline.
ilse
procedure call to out-of-line code
That's just in terms of avoiding object code bloat ... a pair of
instructions in-lined for a constant gpio will cost as much space
as the procedure call, but that logic hiding behind the GPLR(),
GPSR(), and GPCR() macros is another thing altogether.
> So what is the state of this discussion, now that 2.6.19 is here?
My understanding is that nobody objected to the GPIO calls, and several
folk see active goodness in having them. Notably Haavard, wanting to
have a driver that works on both AVR32 and AT91 (different SOC arch,
same controller IP), you (different ARM platforms), Bill Gatliff (for
ISTR some code shared between ARM and PPC platforms), and a few others.
The pushback has been entirely related to pin muxing, and I think it's
accepted now that muxing is platform-specific and orthogonal ... doesn't
need to hold up a common API here.
> I just submitted an input driver for GPIO buttons to linux-input that
> we use in the handhelds.org kernel for sa1100, pxa and s3c2410 archs.
> It needs some ugly
> #ifdefs currently, but with common GPIO calls they all could go away.
Onless there are better suggestions, I think what I'll do is submit
a pair of patches:
- The documentation, with <asm-arm/gpio.h>
- OMAP-specific implementation
Then I'll send an FYI to the ARM list (since so many ARMs could use this!)
and ask Andrew to merge that, first to MM then into 2.6.20 before RC1.
Then I'll ask you to submit an updated PXA patch, plus preferably
sa1100 and s3c2410 versions, ditto. (If you can get other folk to
help, more power to you!)
And Haavard to submit an AVR32 patch, and corresponding AT91 patch
(ISTR he promised both), ditto.
When those patches are in the MM tree I'd see no particular reason
to hold back on the upstream merge. The folk on the CC list are
involved in maintaining platforms that would be affected, and there
have been no nay-sayers, so I believe nobody is objecting.
Once they're upstream, it's business as usual: drivers can start
using these calls wherever they make sense, platforms can start to
support them, and so on.
- Dave
On Thu, 30 Nov 2006 11:05:00 -0800
David Brownell <[email protected]> wrote:
> On Tuesday 28 November 2006 4:36 am, Haavard Skinnemoen wrote:
> > Here's another go at an implementation of the arch-neutral GPIO API
> > for AVR32. I've also thrown in the pin configuration stuff so that
> > you can see how all the pieces fit together.
>
> That looks good, but it was probably better in a "portmux.h" header.
> (Although the at32_* prefixes help a lot!) You don't use the flags
> AT32_GPIO_PULLUP etc, either.
Indeed, seems like I forgot to actually use those flags. The idea is
that the pinmux configuration functions set up the initial pin state to
avoid any toggling or floating before they are fully configured. This is
how I intended to use them in at32_select_gpio():
pio_writel(pio, PUER, mask);
if (flags & AT32_GPIOF_HIGH)
pio_writel(pio, SODR, mask);
else
pio_writel(pio, CODR, mask);
if (flags & AT32_GPIOF_OUTPUT)
pio_writel(pio, OER, mask);
else
pio_writel(pio, ODR, mask);
pio_writel(pio, PER, mask);
if (!(flags & AT32_GPIOF_PULLUP))
pio_writel(pio, PUDR, mask);
/* It's now allowed to use request_gpio on this pin */
clear_bit(pin_index, &pio->gpio_mask);
> Other than that pinmux confusion, this looks pretty much OK to me.
> The GPIO stuff matches the proposal.
That's good to hear.
> > Even though it is possible to tell from the hardware whether a pin
> > is set up for GPIO, I decided to use two allocation bitmasks per pio
> > controller to keep track of what the pins are used for: pinmux_mask
> > and gpio_mask.
> >
> > pinmux_mask indicates which pins have been configured for usage
> > either by a peripheral or GPIO. If the corresponding bit is set
> > when trying to configure a pin, a warning will be printed along
> > with a stack dump (no BUG anymore.)
>
> That is, pins without that set are still configured how the bootloader
> left them ... possibly as they were left by system reset. On some
> systems it might be desirable to warn when the mode Linux wants isn't
> what the bootloader left, so that all the muxing code can be left out
> of Linux. (Not that it can save much on AT91 or AVR32, but the
> bootloader was probably writing those registers anyway, and saving
> codespace and boot time tends to be a Good Thing.) Or so that Linux
> can't, oh, change the state of the GPIO that keeps the saw switched
> off. ;)
I always figured it's best to start from a clean slate and not depend
on the bootloader to set up things the way Linux wants it. If there's
a saw connected, the board code better make sure that it stays switched
off (which should be easy to do using the "initial state" flags
mentioned above.)
> I notice you didn't have a way to return pins to an "unclaimed" state
> though, which would probably be disadvantageous in some cases. I
> don't agree with the arguments made by Paul Mundt that such usage
> would be a common thing ... but on the other hand, I bet you'd get
> complaints from various folk if you make re-muxing excessively
> painful.
I'll add functions for "unclaiming" pins whenever someone complains,
ok? I don't want to add functions that aren't going to be used any time
soon, and unclaiming pins probably won't be enough -- we need a
mechanism to tell the driver for the device using those pins to
deinitialize itself as well.
> > gpio_mask indicates which pins are available for GPIO. It starts
> > out as all ones, and whenever a pin is configured for GPIO, the
> > corresponding bit is cleared. gpio_request() test_and_set()s a bit
> > in the mask corresponding to the pin being requested, and if it's
> > already set (either because it hasn't been configured or because
> > it's been requested by a different driver), gpio_request() returns
> > an error value.
>
> Sounds OK. You are thus _requiring_ the pin muxing to have been
> done before the gpio pin is requested ... sort of complicates the
> "Linux uses bootloader's pin muxing" model.
Right. I never really thought much about that model, but I imagine
we'll have to make sure the bootloader sets up a sane configuration
before we start depending on it. So I'd rather keep this requirement at
least for now.
If we decide to move the pin muxing responsibility to the bootloader, I
think we need a transitional phase where Linux sanity-checks the
configuration and warns (and possibly fixes up) the PIO if it's not set
up as expected.
> > static inline void configure_usart0_pins(void)
> > {
> > - portmux_set_func(PIOA, 8, FUNC_B); /* RXD */
> > - portmux_set_func(PIOA, 9, FUNC_B); /* TXD */
> > + select_peripheral(PA(8), PERIPH_B, 0); /*
> > RXD */
> > + select_peripheral(PA(9), PERIPH_B, 0); /*
> > TXD */
>
> A constant like PULLUP_OFF would be clearer in these cases.
Yeah, but I really want to fit everything on a single line. I'll see if
I can spare some room for it.
Although...there are several flags that can be set here. Should I
define OUTPUT_OFF and LOW as well? I sort of think it makes sense to
specify "0" as "nothing special".
> > +void __init at32_select_periph(unsigned int pin, unsigned int
> > periph,
> > + int use_pullup)
>
> Declared as "flags" elsewhere, not "use_pullup"...
Right. I messed up the header guards, so gcc didn't warm me that the
definitions were different from the declarations. I guess I should start
building stuff with -Wmissing-prototypes to catch mistakes like this.
The declarations in gpio.h are the correct ones.
Anyway, I obviously agree with your plan to get the GPIO API merged
into mainline. I'll fix this patch and submit one for AT91 as well.
Haavard
Based on earlier discussion, I'm sending a refresh of the generic GPIO
patch, with several (ARM based) implementations in separate patches:
- Core patch, doc + <asm-arm/gpio.h> + <asm-generic/gpio.h>
- OMAP implementation
- AT91 implementation
- PXA implementation
- SA1100 implementation
- S3C2410 implementation
I know there's an AVR32 implementation too; and there's been interest
in this for some PPC support as well.
This time I'm proposing that at least the core patch go into the MM
tree; I think there's been enough discussion, and a general acceptance
that we need this kind of API. Russell usually wants ARM patches to
go through his system, so those implementations above should probably
not go through MM.
With the exception of the AT91 implementation, those are all trivial
wrappers around the existing calls ... which should highlight the fact
that this API reflects existing practice, but with more generic syntax.
AT91 differed only because it needed to split out a "configure as GPIO"
primitive, not merged with the "set gpio direction" call.
Other than clarifications, the main change in the doc is defining
new calls safe for use with GPIOs on things like pcf8574 I2C gpio
expanders; those new calls can sleep, but are otherwise the same as
the spinlock-safe versions. The implementations above implement that
as a wrapper (the asm-generic header) around the spinlock-safe calls.
This API is orthogonal to pin configuration (configure ball X17 as
GPIO 23 rather than R33, with pulldown, etc) which is in any case
highly platform-specific.
Also, as an API rather than an implementation framework, this does
not expose a notion of a "GPIO controller", of which any given
system might have several. It's allowed by the API (e.g. see the
OMAP code), but is not required. I expect that sort of thing will
come later; it's common enough to have SOC-based boards with GPIOs
on the SOC as well as a couple external chips.
- Dave
This defines a simple and minimalist programming interface for GPIO APIs:
- Documentation/gpio.txt ... describes things (read it)
- include/asm-arm/gpio.h ... defines the ARM hook, which just punts
to <asm/arch/gpio.h> for any implementation
- include/asm-generic/gpio.h ... implement "can sleep" variants as calling
the normal ones, for systems that don't handle i2c expanders.
The immediate need for such a cross-architecture API convention is to support
drivers that work the same on AT91 ARM and AVR32 AP7000 chips, which embed many
of the same controllers but have different CPUs. However, several other users
have been reported, including a driver for a hardware watchdog chip and some
handhelds.org multi-CPU button drivers.
Signed-off-by: David Brownell <[email protected]>
---
Since the last version posted, the doc has been updated and clarified,
and has changed to include new "cansleep" variants of GPIO accessors
that are appropriate for all those I2C GPIO expanders.
The OMAP sample implementation has been split out.
The focus still remains the API, not techniques used to implement platforms
supporting multiple GPIO controllers. That can be done later, if needed.
Index: osk/Documentation/gpio.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/Documentation/gpio.txt 2006-12-17 16:56:43.000000000 -0800
@@ -0,0 +1,271 @@
+GPIO Interfaces
+
+This provides an overview of GPIO access conventions on Linux.
+
+
+What is a GPIO?
+===============
+A "General Purpose Input/Output" (GPIO) is a flexible software-controlled
+digital signal. They are provided from many kinds of chip, and are familiar
+to Linux developers working with embedded and custom hardware. Each GPIO
+represents a bit connected to a particular pin, or "ball" on Ball Grid Array
+(BGA) packages. Board schematics show which external hardware connects to
+which GPIOs. Drivers can be written generically, so that board setup code
+passes such pin configuration data to drivers.
+
+System-on-Chip (SOC) processors heavily rely on GPIOs. In some cases, every
+non-dedicated pin can be configured as a GPIO; and most chips have at least
+several dozen of them. Programmable logic devices (like FPGAs) can easily
+provide GPIOs; multifunction chips like power managers, and audio codecs
+often have a few such pins to help with pin scarcity on SOCs; and there are
+also "GPIO Expander" chips that connect using the I2C or SPI serial busses.
+Most PC southbridges have a few dozen GPIO-capable pins (with only the BIOS
+firmware knowing how they're used).
+
+The exact capabilities of GPIOs vary between systems. Common options:
+
+ - Output values are writable (high=1, low=0). Some chips also have
+ options about how that value is driven, so that for example only one
+ value might be driven ... supporting "wire-OR" and similar schemes
+ for the other value.
+
+ - Input values are likewise readable (1, 0). Some chips support readback
+ of pins configured as "output", which is very useful in such "wire-OR"
+ cases (to support bidirectional signaling). GPIO controllers may have
+ input de-glitch logic, sometimes with software controls.
+
+ - Inputs can often be used as IRQ signals, often edge triggered but
+ sometimes level triggered. Such IRQs may be configurable as system
+ wakeup events, to wake the system from a low power state.
+
+ - Usually a GPIO will be configurable as either input or output, as needed
+ by different product boards; single direction ones exist too.
+
+ - Most GPIOs can be accessed while holding spinlocks, but those accessed
+ through a serial bus normally can't. Some systems support both types.
+
+On a given board each GPIO is used for one specific purpose like monitoring
+MMC/SD card insertion/removal, detecting card writeprotect status, driving
+a LED, configuring a transceiver, bitbanging a serial bus, poking a hardware
+watchdog, sensing a switch, and so on.
+
+
+GPIO conventions
+================
+Note that this is called a "convention" because you don't need to do it this
+way, and it's no crime if you don't. There **are** cases where portability
+is not the main issue; GPIOs are often used for the kind of board-specific
+glue logic that may even change between board revisions, and can't ever be
+used on a board that's wired differently. Only least-common-denominator
+functionality can be very portable. Other features are platform-specific,
+and that can be critical for glue logic.
+
+Plus, this doesn't define an implementation framework, just an interface.
+One platform might implement it as simple inline functions accessing chip
+registers; another might implement it by delegating through abstractions
+used for several very different kinds of GPIO controller.
+
+That said, if the convention is supported on their platform, drivers should
+use it when possible:
+
+ #include <asm/gpio.h>
+
+If you stick to this convention then it'll be easier for other developers to
+see what your code is doing, and help maintain it.
+
+
+Identifying GPIOs
+-----------------
+GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
+reserves "negative" numbers for other purposes like marking signals as
+"not available on this board", or indicating faults.
+
+Platforms define how they use those integers, and usually #define symbols
+for the GPIO lines so that board-specific setup code directly corresponds
+to the relevant schematics. In contrast, drivers should only use GPIO
+numbers passed to them from that setup code, using platform_data to hold
+board-specific pin configuration data (along with other board specific
+data they need). That avoids portability problems.
+
+So for example one platform uses numbers 32-159 for GPIOs; while another
+uses numbers 0..63 with one set of GPIO controllers, 64-79 with another
+type of GPIO controller, and on one particular board 80-95 with an FPGA.
+The numbers need not be contiguous; either of those platforms could also
+use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders.
+
+Whether a platform supports multiple GPIO controllers is currently a
+platform-specific implementation issue.
+
+
+Using GPIOs
+-----------
+One of the first things to do with a GPIO, often in board setup code when
+setting up a platform_device using the GPIO, is mark its direction:
+
+ /* set as input or output, returning 0 or negative errno */
+ int gpio_direction_input(unsigned gpio);
+ int gpio_direction_output(unsigned gpio);
+
+The return value is zero for success, else a negative errno. It should
+be checked, since the get/set calls don't have error returns and since
+misconfiguration is possible. (These calls could sleep.)
+
+Setting the direction can fail if the GPIO number is invalid, or when
+that particular GPIO can't be used in that mode. It's generally a bad
+idea to rely on boot firmware to have set the direction correctly, since
+it probably wasn't validated to do more than boot Linux. (Similarly,
+that board setup code probably needs to multiplex that pin as a GPIO,
+and configure pullups/pulldowns appropriately.)
+
+
+Spinlock-Safe GPIO access
+-------------------------
+Most GPIO controllers can be accessed with memory read/write instructions.
+That doesn't need to sleep, and can safely be done from inside IRQ handlers.
+
+Use these calls to access such GPIOs:
+
+ /* GPIO INPUT: return zero or nonzero */
+ int gpio_get_value(unsigned gpio);
+
+ /* GPIO OUTPUT */
+ void gpio_set_value(unsigned gpio, int value);
+
+The values are boolean, zero for low, nonzero for high. When reading the
+value of an output pin, the value returned should be what's seen on the
+pin ... that won't always match the specified output value, because of
+issues including wire-OR and output latencies.
+
+The get/set calls have no error returns because "invalid GPIO" should have
+been reported earlier in gpio_set_direction(). However, note that not all
+platforms can read the value of output pins; those that can't should always
+return zero. Also, these calls will be ignored for GPIOs that can't safely
+be accessed wihtout sleeping (see below).
+
+Platform-specific implementations are encouraged to optimise the two
+calls to access the GPIO value in cases where the GPIO number (and for
+output, value) are constant. It's normal for them to need only a couple
+of instructions in such cases (reading or writing a hardware register),
+and not to need spinlocks. Such optimized calls can make bitbanging
+applications a lot more efficient (in both space and time) than spending
+dozens of instructions on subroutine calls.
+
+
+GPIO access that may sleep
+--------------------------
+Some GPIO controllers must be accessed using message based busses like I2C
+or SPI. Commands to read or write those GPIO values require waiting to
+get to the head of a queue to transmit a command and get its response.
+This requires sleeping, which can't be done from inside IRQ handlers.
+
+Platforms that support this type of GPIO distinguish them from other GPIOs
+by returning nonzero from this call:
+
+ int gpio_cansleep(unsigned gpio);
+
+To access such GPIOs, a different set of accessors is defined:
+
+ /* GPIO INPUT: return zero or nonzero, might sleep */
+ int gpio_get_value_cansleep(unsigned gpio);
+
+ /* GPIO OUTPUT, might sleep */
+ void gpio_set_value_cansleep(unsigned gpio, int value);
+
+Other than the fact that these calls might sleep, and will not be ignored
+for GPIOs that can't be accessed from IRQ handlers, these calls act the
+same as the spinlock-safe calls.
+
+
+Claiming and Releasing GPIOs (OPTIONAL)
+---------------------------------------
+To help catch system configuration errors, two calls are defined.
+However, many platforms don't currently support this mechanism.
+
+ /* request GPIO, returning 0 or negative errno.
+ * non-null labels may be useful for diagnostics.
+ */
+ int gpio_request(unsigned gpio, const char *label);
+
+ /* release previously-claimed GPIO */
+ void gpio_free(unsigned gpio);
+
+Passing invalid GPIO numbers to gpio_request() will fail, as will requesting
+GPIOs that have already been claimed with that call. The return value of
+gpio_request() must be checked. (These calls could sleep.)
+
+These calls serve two basic purposes. One is marking the signals which
+are actually in use as GPIOs, for better diagnostics; systems may have
+several hundred potential GPIOs, but often only a dozen are used on any
+given board. Another is to catch conflicts between drivers, reporting
+errors when drivers wrongly think they have exclusive use of that signal.
+
+These two calls are optional because not not all current Linux platforms
+offer such functionality in their GPIO support; a valid implementation
+could return success for all gpio_request() calls. Unlike the other calls,
+the state they represent doesn't normally match anything from a hardware
+register; it's just a software bitmap which clearly is not necessary for
+correct operation of hardware or (bug free) drivers.
+
+Note that requesting a GPIO does NOT cause it to be configured in any
+way; it just marks that GPIO as in use. Separate code must handle any
+pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
+
+
+GPIOs mapped to IRQs
+--------------------
+GPIO numbers are unsigned integers; so are IRQ numbers. These make up
+two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can
+map between them using calls like:
+
+ /* map GPIO numbers to IRQ numbers */
+ int gpio_to_irq(unsigned gpio);
+
+ /* map IRQ numbers to GPIO numbers */
+ int irq_to_gpio(unsigned irq);
+
+Those return either the corresponding number in the other namespace, or
+else a negative errno code if the mapping can't be done. (For example,
+some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
+number that hasn't been marked as an input using gpio_set_direction(), or
+to use an IRQ number that didn't originally come from gpio_to_irq().
+
+These two mapping calls are expected to cost on the order of a single
+addition or subtraction. They're not allowed to sleep.
+
+Non-error values returned from gpio_to_irq() can be passed to request_irq()
+or free_irq(). They will often be stored into IRQ resources for platform
+devices, by the board-specific initialization code. Note that IRQ trigger
+options are part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are
+system wakeup capabilities.
+
+Non-error values returned from irq_to_gpio() would most commonly be used
+with gpio_get_value().
+
+
+
+What do these conventions omit?
+===============================
+One of the biggest things these conventions omit is pin multiplexing, since
+this is highly chip-specific and nonportable. One platform might not need
+explicit multiplexing; another might have just two options for use of any
+given pin; another might have eight options per pin; another might be able
+to route a given GPIO to any one of several pins. (Yes, those examples all
+come from systems that run Linux today.)
+
+Related to multiplexing is configuration and enabling of the pullups or
+pulldowns integrated on some platforms. Not all platforms support them,
+or support them in the same way; and any given board might use external
+pullups (or pulldowns) so that the on-chip ones should not be used.
+
+There are other system-specific mechanisms that are not specified here,
+like the aforementioned options for input de-glitching and wire-OR output.
+Hardware may support reading or writing GPIOs in gangs, but that's usually
+configuration dependednt: for GPIOs sharing the same bank. (GPIOs are
+commonly grouped in banks of 16 or 32, with a given SOC having several such
+banks.) Code relying on such mechanisms will necessarily be nonportable.
+
+Dynamic definition of GPIOs is not currently supported; for example, as
+a side effect of configuring an add-on board with some GPIO expanders.
+
+These calls are purely for kernel space, but a userspace API could be built
+on top of it.
Index: osk/include/asm-arm/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/include/asm-arm/gpio.h 2006-12-15 03:59:41.000000000 -0800
@@ -0,0 +1,7 @@
+#ifndef _ARCH_ARM_GPIO_H
+#define _ARCH_ARM_GPIO_H
+
+/* not all ARM platforms necessarily support this API ... */
+#include <asm/arch/gpio.h>
+
+#endif /* _ARCH_ARM_GPIO_H */
Index: osk/include/asm-generic/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ osk/include/asm-generic/gpio.h 2006-12-17 16:53:18.000000000 -0800
@@ -0,0 +1,25 @@
+#ifndef _ASM_GENERIC_GPIO_H
+#define _ASM_GENERIC_GPIO_H
+
+/* platforms that don't directly support access to GPIOs through I2C, SPI,
+ * or other blocking infrastructure can use these wrappers.
+ */
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+ return 0;
+}
+
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+ might_sleep();
+ return gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+ might_sleep();
+ gpio_set_value(gpio, value);
+}
+
+#endif /* _ASM_GENERIC_GPIO_H */
This teaches OMAP how to implement the cross-platform GPIO interfaces.
Signed-off-by: David Brownell <[email protected]>
Index: at91/include/asm-arm/arch-omap/gpio.h
===================================================================
--- at91.orig/include/asm-arm/arch-omap/gpio.h 2006-12-19 01:45:33.000000000 -0800
+++ at91/include/asm-arm/arch-omap/gpio.h 2006-12-19 02:06:11.000000000 -0800
@@ -76,4 +76,58 @@ extern void omap_set_gpio_direction(int
extern void omap_set_gpio_dataout(int gpio, int enable);
extern int omap_get_gpio_datain(int gpio);
+/*-------------------------------------------------------------------------*/
+
+/* wrappers for "new style" GPIO calls. the old OMAP-specfic ones should
+ * eventually be removed (along with this errno.h inclusion), and maybe
+ * gpios should put MPUIOs last too.
+ */
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+ { return omap_request_gpio(gpio); }
+
+static inline void gpio_free(unsigned gpio)
+ { omap_free_gpio(gpio); }
+
+
+static inline int __gpio_set_direction(unsigned gpio, int is_input)
+{
+ if (cpu_class_is_omap2()) {
+ if (gpio > OMAP_MAX_GPIO_LINES)
+ return -EINVAL;
+ } else {
+ if (gpio > (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */))
+ return -EINVAL;
+ }
+ omap_set_gpio_direction(gpio, is_input);
+ return 0;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+ { return __gpio_set_direction(gpio, 1); }
+
+static inline int gpio_direction_output(unsigned gpio)
+ { return __gpio_set_direction(gpio, 0); }
+
+
+static inline int gpio_get_value(unsigned gpio)
+ { return omap_get_gpio_datain(gpio); }
+
+static inline void gpio_set_value(unsigned gpio, int value)
+ { omap_set_gpio_dataout(gpio, value); }
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+static inline int gpio_to_irq(unsigned gpio)
+ { return OMAP_GPIO_IRQ(gpio); }
+
+static inline int irq_to_gpio(unsigned irq)
+{
+ if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
+ return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
+ return irq - IH_GPIO_BASE;
+}
+
#endif
This is a first cut at making the AT91 code use the generic GPIO calls.
Note that the original AT91 GPIO calls merged the "mux pin as GPIO"
and "set GPIO direction" functionality into one API call, contrary
to what's specified as a cross-platform portable model. So this
involved a few non-inlinable functions.
Signed-off-by: David Brownell <[email protected]>
Index: at91/include/asm-arm/arch-at91rm9200/gpio.h
===================================================================
--- at91.orig/include/asm-arm/arch-at91rm9200/gpio.h 2006-12-20 11:22:10.000000000 -0800
+++ at91/include/asm-arm/arch-at91rm9200/gpio.h 2006-12-20 11:22:33.000000000 -0800
@@ -179,6 +179,7 @@
#ifndef __ASSEMBLY__
/* setup setup routines, called from board init or driver probe() */
+extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
@@ -193,7 +194,41 @@ extern int at91_get_gpio_value(unsigned
/* callable only from core power-management code */
extern void at91_gpio_suspend(void);
extern void at91_gpio_resume(void);
-#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* wrappers for "new style" GPIO calls. the old AT91-specfic ones should
+ * eventually be removed (along with this errno.h inclusion), and the
+ * gpio request/free calls should probably be implemented.
+ */
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+ { return 0; }
+
+static inline void gpio_free(unsigned gpio)
+ { }
+
+
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio);
+
+static inline int gpio_get_value(unsigned gpio)
+ { return at91_get_gpio_value(gpio); }
+
+static inline void gpio_set_value(unsigned gpio, int value)
+ { (void) at91_set_gpio_value(gpio, value); }
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+static inline int gpio_to_irq(unsigned gpio)
+ { return gpio; }
+
+static inline int irq_to_gpio(unsigned irq)
+ { return irq; }
+
+#endif /* __ASSEMBLY__ */
#endif
Index: at91/arch/arm/mach-at91rm9200/gpio.c
===================================================================
--- at91.orig/arch/arm/mach-at91rm9200/gpio.c 2006-12-20 11:22:10.000000000 -0800
+++ at91/arch/arm/mach-at91rm9200/gpio.c 2006-12-20 11:31:28.000000000 -0800
@@ -66,6 +66,24 @@ static inline unsigned pin_to_mask(unsig
/*
+ * mux the pin to the "GPIO" peripheral role.
+ */
+int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup)
+{
+ void __iomem *pio = pin_to_controller(pin);
+ unsigned mask = pin_to_mask(pin);
+
+ if (!pio)
+ return -EINVAL;
+ __raw_writel(mask, pio + PIO_IDR);
+ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+ __raw_writel(mask, pio + PIO_PER);
+ return 0;
+}
+EXPORT_SYMBOL(at91_set_GPIO_periph);
+
+
+/*
* mux the pin to the "A" internal peripheral role.
*/
int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
@@ -182,6 +200,36 @@ EXPORT_SYMBOL(at91_set_multi_drive);
/*--------------------------------------------------------------------------*/
+/* new-style GPIO calls; these expect at91_set_GPIO_periph to have been
+ * called, and maybe at91_set_multi_drive() for putout pins.
+ */
+
+int gpio_direction_input(unsigned pin)
+{
+ void __iomem *pio = pin_to_controller(pin);
+ unsigned mask = pin_to_mask(pin);
+
+ if (!pio || !(__raw_readl(pio + PIO_PSR) & mask))
+ return -EINVAL;
+ __raw_writel(mask, pio + PIO_OER);
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned pin)
+{
+ void __iomem *pio = pin_to_controller(pin);
+ unsigned mask = pin_to_mask(pin);
+
+ if (!pio || !(__raw_readl(pio + PIO_PSR) & mask))
+ return -EINVAL;
+ __raw_writel(mask, pio + PIO_OER);
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+/*--------------------------------------------------------------------------*/
+
/*
* assuming the pin is muxed as a gpio output, set its value.
*/
Arch-neutral GPIO calls for SA-1100.
From: Philipp Zabel <[email protected]>
Index: at91/include/asm-arm/arch-sa1100/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ at91/include/asm-arm/arch-sa1100/gpio.h 2006-12-19 02:09:08.000000000 -0800
@@ -0,0 +1,81 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * SA1100 GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_SA1100_GPIO_H
+#define __ASM_ARCH_SA1100_GPIO_H
+
+#include <asm/arch/SA-1100.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ if (gpio > GPIO_MAX)
+ return -EINVAL;
+ GPDR = (GPDR_In << gpio) 0
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ if (gpio > GPIO_MAX)
+ return -EINVAL;
+ GPDR = (GPDR_Out << gpio) 0
+}
+
+#define gpio_get_value(gpio) \
+ (GPLR & GPIO_GPIO(gpio))
+
+#define gpio_set_value(gpio,value) \
+ ((value) ? (GPSR = GPIO_GPIO(gpio)) : (GPCR(gpio) = GPIO_GPIO(gpio)))
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+static inline unsigned gpio_to_irq(unsigned gpio)
+{
+ if (gpio < 11)
+ return IRQ_GPIO0 + gpio;
+ else
+ return IRQ_GPIO11 - 11 + gpio;
+}
+
+static inline unsigned irq_to_gpio(unsigned irq)
+{
+ if (irq < IRQ_GPIO11_27)
+ return irq - IRQ_GPIO0;
+ else
+ return irq - IRQ_GPIO11 + 11;
+}
+
+#endif
Arch-neutral GPIO calls for PXA.
From: Philipp Zabel <[email protected]>
Index: at91/include/asm-arm/arch-pxa/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ at91/include/asm-arm/arch-pxa/gpio.h 2006-12-19 02:06:39.000000000 -0800
@@ -0,0 +1,72 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * PXA GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_PXA_GPIO_H
+#define __ASM_ARCH_PXA_GPIO_H
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+ pxa_gpio_mode(gpio | GPIO_IN);
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+ pxa_gpio_mode(gpio | GPIO_OUT);
+}
+
+/* REVISIT these macros are correct, but suffer code explosion
+ * for non-constant parameters. Provide out-line versions too.
+ */
+#define gpio_get_value(gpio) \
+ (GPLR(gpio) & GPIO_bit(gpio))
+
+#define gpio_set_value(gpio,value) \
+ ((value) ? (GPSR(gpio) = GPIO_bit(gpio)):(GPCR(gpio) = GPIO_bit(gpio)))
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
+#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
+
+
+#endif
Arch-neutral GPIO calls for S3C24xx.
From: Philipp Zabel <[email protected]>
Index: at91/include/asm-arm/arch-s3c2410/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ at91/include/asm-arm/arch-s3c2410/gpio.h 2006-12-19 02:05:52.000000000 -0800
@@ -0,0 +1,65 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * S3C2400 GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_PXA_GPIO_H
+#define __ASM_ARCH_PXA_GPIO_H
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_INPUT);
+ return 0;
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_OUTPUT);
+ return 0;
+}
+
+#define gpio_get_value(gpio) s3c2410_gpio_getpin(gpio)
+#define gpio_set_value(gpio,value) s3c2410_gpio_setpin(gpio, value)
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+/* FIXME or maybe s3c2400_gpio_getirq() ... */
+#define gpio_to_irq(gpio) s3c2410_gpio_getirq(gpio)
+
+/* FIXME implement irq_to_gpio() */
+
+#endif
On 12/20/06, David Brownell <[email protected]> wrote:
> Based on earlier discussion, I'm sending a refresh of the generic GPIO
> patch, with several (ARM based) implementations in separate patches:
>
> - Core patch, doc + <asm-arm/gpio.h> + <asm-generic/gpio.h>
> - OMAP implementation
> - AT91 implementation
> - PXA implementation
> - SA1100 implementation
> - S3C2410 implementation
>
> I know there's an AVR32 implementation too; and there's been interest
> in this for some PPC support as well.
Great, thanks Dave. Unfortunately, I'm going to be more or less
offline for the rest of the year, but FWIW, the AVR32 implementation
is already in -mm as part of git-avr32.patch. I guess I should check
and see if it's in sync with the rest.
I'll refresh the atmel_spi patch when I get back to work in january.
Haavard
On Wednesday 20 December 2006 3:30 pm, H?vard Skinnemoen wrote:
> On 12/20/06, David Brownell <[email protected]> wrote:
> > Based on earlier discussion, I'm sending a refresh of the generic GPIO
> > patch, with several (ARM based) implementations in separate patches:
> >
> > - Core patch, doc + <asm-arm/gpio.h> + <asm-generic/gpio.h>
> > - OMAP implementation
> > - AT91 implementation
> > - PXA implementation
> > - SA1100 implementation
> > - S3C2410 implementation
> >
> > I know there's an AVR32 implementation too; and there's been interest
> > in this for some PPC support as well.
>
> Great, thanks Dave. Unfortunately, I'm going to be more or less
> offline for the rest of the year, but FWIW, the AVR32 implementation
> is already in -mm as part of git-avr32.patch.
That's appropriate; after all, as a programming interface, it's
appropriate that there be multiple implementations! Presumably
that doc is missing, but the API calls _should_ make sense on
their own.
> I guess I should check
> and see if it's in sync with the rest.
I'd at most expect you're missing an #include <asm-generic/gpio.h>
for the cansleep variants ... which only got added because folk
agreed such spinlock-unsafe calls were needed, not because anyone
had a pressing near-term need for them. (Unlike the spinlock-safe
functionality, which is _very_ widely implemented.)
> I'll refresh the atmel_spi patch when I get back to work in january.
Heh, maybe I can even try it out by then. ;)
- Dave
On Wed, 20 Dec 2006 13:11:19 -0800
David Brownell <[email protected]> wrote:
> +static inline int gpio_get_value(unsigned gpio)
> + { return at91_get_gpio_value(gpio); }
> +
> +static inline void gpio_set_value(unsigned gpio, int value)
> + { (void) at91_set_gpio_value(gpio, value); }
whaa? Where'd we pull that coding style from?
Please,
static inline int gpio_get_value(unsigned gpio)
{
return at91_get_gpio_value(gpio);
}
static inline void gpio_set_value(unsigned gpio, int value)
{
at91_set_gpio_value(gpio, value);
}
On Wed, 20 Dec 2006 13:12:35 -0800
David Brownell <[email protected]> wrote:
> +/* REVISIT these macros are correct, but suffer code explosion
> + * for non-constant parameters. Provide out-line versions too.
> + */
> +#define gpio_get_value(gpio) \
> + (GPLR(gpio) & GPIO_bit(gpio))
> +
> +#define gpio_set_value(gpio,value) \
> + ((value) ? (GPSR(gpio) = GPIO_bit(gpio)):(GPCR(gpio) = GPIO_bit(gpio)))
Why not implement them as inline functions?
Or non-inline functions, come to that.
Either way, programming in C is preferable to this ;)
On Wed, 20 Dec 2006 13:13:21 -0800
David Brownell <[email protected]> wrote:
> +#define gpio_get_value(gpio) \
> + (GPLR & GPIO_GPIO(gpio))
> +
> +#define gpio_set_value(gpio,value) \
> + ((value) ? (GPSR = GPIO_GPIO(gpio)) : (GPCR(gpio) = GPIO_GPIO(gpio)))
likewise.
On Wednesday 20 December 2006 10:12 pm, Andrew Morton wrote:
> On Wed, 20 Dec 2006 13:12:35 -0800
> David Brownell <[email protected]> wrote:
>
> > +/* REVISIT these macros are correct, but suffer code explosion
> > + * for non-constant parameters. Provide out-line versions too.
> > + */
> > +#define gpio_get_value(gpio) \
> > + (GPLR(gpio) & GPIO_bit(gpio))
> > +
> > +#define gpio_set_value(gpio,value) \
> > + ((value) ? (GPSR(gpio) = GPIO_bit(gpio)):(GPCR(gpio) = GPIO_bit(gpio)))
>
> Why not implement them as inline functions?
I just collected and forwarded the code from Philip...
the better not to lose such stuff! :)
> Or non-inline functions, come to that.
In this case I think that'd be preferable; see what those macros
expand to on pxa27x CPUs.
> Either way, programming in C is preferable to this ;)
Hey, at least we've started using these new fangled "function prototypes"!
I remember when we had to walk five miles through LINT every morning.
Uphill. Then it was another five miles uphill on the way back, through
a maze of twisty octal contants like "8" and "9". We didn't even have
void pointers. UIDs were eight bits. This ANSI stuff you new kids are
using ... you've got it easy!!
On Wednesday 20 December 2006 10:10 pm, Andrew Morton wrote:
> On Wed, 20 Dec 2006 13:11:19 -0800
> David Brownell <[email protected]> wrote:
>
> > +static inline int gpio_get_value(unsigned gpio)
> > + { return at91_get_gpio_value(gpio); }
> > +
> > +static inline void gpio_set_value(unsigned gpio, int value)
> > + { (void) at91_set_gpio_value(gpio, value); }
>
> whaa? Where'd we pull that coding style from?
School of concision. Notice also the clever ";) at the end of each line.
> Please,
I see you fixed this in what you merged to MM; thanks.
- Dave
> static inline int gpio_get_value(unsigned gpio)
> {
> return at91_get_gpio_value(gpio);
> }
>
> static inline void gpio_set_value(unsigned gpio, int value)
> {
> at91_set_gpio_value(gpio, value);
> }
>
(adding Ben Dooks as he's taking care of s3c24xx stuff)
David Brownell <[email protected]> writes:
Note that I neither tested it nor build tested it. It's only remarks I
have when I read the code.
> Arch-neutral GPIO calls for S3C24xx.
>
> From: Philipp Zabel <[email protected]>
>
> Index: at91/include/asm-arm/arch-s3c2410/gpio.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ at91/include/asm-arm/arch-s3c2410/gpio.h 2006-12-19 02:05:52.000000000 -0800
> @@ -0,0 +1,65 @@
> +/*
> + * linux/include/asm-arm/arch-pxa/gpio.h
arch-pxa ? forgot to change it ? :)
> + *
> + * S3C2400 GPIO wrappers for arch-neutral GPIO calls
you meant S3C2410 ?
> + *
> + * Written by Philipp Zabel <[email protected]>
> + *
> + * 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
> + *
> + */
> +
> +#ifndef __ASM_ARCH_PXA_GPIO_H
> +#define __ASM_ARCH_PXA_GPIO_H
pxa again :(
> +
> +#include <asm/arch/pxa-regs.h>
That's annoying. include/asm-arm/arch-s3c2410/pxa-regs.h doesn't
exist. Lack of build testing ?
> +#include <asm/arch/irqs.h>
imho, this is not needed. The user who will use irq will add it in his
code anyway.
> +#include <asm/arch/hardware.h>
> +
> +#include <asm/errno.h>
Is it really needed ?
> +
> +static inline int gpio_request(unsigned gpio, const char *label)
> +{
> + return 0;
> +}
> +
> +static inline void gpio_free(unsigned gpio)
> +{
> + return;
> +}
> +
> +static inline int gpio_direction_input(unsigned gpio)
> +{
> + s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_INPUT);
> + return 0;
> +}
> +
> +static inline int gpio_direction_output(unsigned gpio)
> +{
> + s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_OUTPUT);
> + return 0;
> +}
> +
> +#define gpio_get_value(gpio) s3c2410_gpio_getpin(gpio)
> +#define gpio_set_value(gpio,value) s3c2410_gpio_setpin(gpio, value)
> +
> +#include <asm-generic/gpio.h> /* cansleep wrappers */
> +
> +/* FIXME or maybe s3c2400_gpio_getirq() ... */
> +#define gpio_to_irq(gpio) s3c2410_gpio_getirq(gpio)
imho, this should be fixed even if the s3c2400 is not 100% supported in
mainline.
Regards,
Arnaud
On Wed, 20 Dec 2006, David Brownell wrote:
> On Wednesday 20 December 2006 10:12 pm, Andrew Morton wrote:
> > Why not implement them as inline functions?
>
> I just collected and forwarded the code from Philip...
> the better not to lose such stuff! :)
>
>
> > Or non-inline functions, come to that.
>
> In this case I think that'd be preferable; see what those macros
> expand to on pxa27x CPUs.
Only if the gpio argument is not constant please. When it is constant
this expands to a single word store.
Nicolas
On 12/21/06, Nicolas Pitre <[email protected]> wrote:
> On Wed, 20 Dec 2006, David Brownell wrote:
>
> > On Wednesday 20 December 2006 10:12 pm, Andrew Morton wrote:
> > > Why not implement them as inline functions?
> >
> > I just collected and forwarded the code from Philip...
> > the better not to lose such stuff! :)
> >
> >
> > > Or non-inline functions, come to that.
> >
> > In this case I think that'd be preferable; see what those macros
> > expand to on pxa27x CPUs.
>
> Only if the gpio argument is not constant please. When it is constant
> this expands to a single word store.
>
>
> Nicolas
David suggested to have both inline and non-inline functions depending
on whether gpio is constant. How is this patch?
regards
Philipp
Index: linux-2.6/include/asm-arm/arch-pxa/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-arm/arch-pxa/gpio.h 2006-12-21
07:57:12.000000000 +0100
@@ -0,0 +1,86 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * PXA GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_PXA_GPIO_H
+#define __ASM_ARCH_PXA_GPIO_H
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+ pxa_gpio_mode(gpio | GPIO_IN);
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+ pxa_gpio_mode(gpio | GPIO_OUT);
+}
+
+static inline int __gpio_get_value(unsigned gpio)
+{
+ return GPLR(gpio) & GPIO_bit(gpio);
+}
+
+#define gpio_get_value(gpio) \
+ (__builtin_constant_p(gpio) ? \
+ __gpioe_get_value(gpio) : \
+ pxa_gpio_get_value(gpio))
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR(gpio) = GPIO_bit(gpio);
+ else
+ GPCR(gpio) = GPIO_bit(gpio);
+}
+
+#define gpio_set_value(gpio,value) \
+ (__builtin_constant_p(gpio) ? \
+ __gpio_set_value(gpio, value) : \
+ pxa_gpio_set_value(gpio, value))
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
+#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
+
+
+#endif
Index: linux-2.6/arch/arm/mach-pxa/generic.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-16
16:47:42.000000000 +0100
+++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-16 16:47:45.000000000 +0100
@@ -129,6 +129,29 @@
EXPORT_SYMBOL(pxa_gpio_mode);
/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+int pxa_gpio_get_value(unsigned gpio)
+{
+ return GPLR(gpio) & GPIO_bit(gpio);
+}
+
+EXPORT_SYMBOL(pxa_gpio_get_value);
+
+/*
+ * Set output GPIO level
+ */
+void pxa_gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR(gpio) = GPIO_bit(gpio);
+ else
+ GPCR(gpio) = GPIO_bit(gpio);
+}
+
+EXPORT_SYMBOL(pxa_gpio_set_value);
+
+/*
* Routine to safely enable or disable a clock in the CKEN
*/
void pxa_set_cken(int clock, int enable)
Index: linux-2.6/include/asm-arm/arch-pxa/hardware.h
===================================================================
--- linux-2.6.orig/include/asm-arm/arch-pxa/hardware.h 2006-12-17
15:42:36.000000000 +0100
+++ linux-2.6/include/asm-arm/arch-pxa/hardware.h 2006-12-17
15:43:26.000000000 +0100
@@ -68,6 +68,16 @@
extern void pxa_gpio_mode( int gpio_mode );
/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+extern int pxa_gpio_get_value(unsigned gpio);
+
+/*
+ * Set output GPIO level
+ */
+extern void pxa_gpio_set_value(unsigned gpio, int value);
+
+/*
* Routine to enable or disable CKEN
*/
extern void pxa_set_cken(int clock, int enable);
On 12/21/06, Arnaud Patard <[email protected]> wrote:
> (adding Ben Dooks as he's taking care of s3c24xx stuff)
>
> David Brownell <[email protected]> writes:
>
>
> Note that I neither tested it nor build tested it. It's only remarks I
> have when I read the code.
Thanks for looking through this. I originally just sent this
(admittedly rushed) patch to [email protected]
to get some eyes on it. Sorry about that.
I have no S3C24xx machine, so I'd like very much somebody
and with some insight to S3C24xx who can test to try and
correct this.
> > Arch-neutral GPIO calls for S3C24xx.
> >
> > From: Philipp Zabel <[email protected]>
> >
> > Index: at91/include/asm-arm/arch-s3c2410/gpio.h
> > ===================================================================
> > --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> > +++ at91/include/asm-arm/arch-s3c2410/gpio.h 2006-12-19 02:05:52.000000000 -0800
> > @@ -0,0 +1,65 @@
> > +/*
> > + * linux/include/asm-arm/arch-pxa/gpio.h
>
> arch-pxa ? forgot to change it ? :)
Exactly.
> > + *
> > + * S3C2400 GPIO wrappers for arch-neutral GPIO calls
>
> you meant S3C2410 ?
I got a little confused with s3c2410 being the name for all s3c24xx
architectures.
> > + *
> > + * Written by Philipp Zabel <[email protected]>
> > + *
> > + * 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
> > + *
> > + */
> > +
> > +#ifndef __ASM_ARCH_PXA_GPIO_H
> > +#define __ASM_ARCH_PXA_GPIO_H
>
> pxa again :(
Not anymore.
> > +
> > +#include <asm/arch/pxa-regs.h>
>
> That's annoying. include/asm-arm/arch-s3c2410/pxa-regs.h doesn't
> exist. Lack of build testing ?
Yes, see above.
> > +#include <asm/arch/irqs.h>
>
> imho, this is not needed. The user who will use irq will add it in his
> code anyway.
Ok.
> > +#include <asm/arch/hardware.h>
> > +
> > +#include <asm/errno.h>
>
> Is it really needed ?
No. I copied this from David's example,
but with gpio_request and gpio_free not
implemented and missing error handling
in s3c2410_gpio_cfgpin, no error codes
are needed.
> > +
> > +static inline int gpio_request(unsigned gpio, const char *label)
> > +{
> > + return 0;
> > +}
> > +
> > +static inline void gpio_free(unsigned gpio)
> > +{
> > + return;
> > +}
> > +
> > +static inline int gpio_direction_input(unsigned gpio)
> > +{
> > + s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_INPUT);
> > + return 0;
> > +}
> > +
> > +static inline int gpio_direction_output(unsigned gpio)
> > +{
> > + s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_OUTPUT);
> > + return 0;
> > +}
> > +
> > +#define gpio_get_value(gpio) s3c2410_gpio_getpin(gpio)
> > +#define gpio_set_value(gpio,value) s3c2410_gpio_setpin(gpio, value)
> > +
> > +#include <asm-generic/gpio.h> /* cansleep wrappers */
> > +
> > +/* FIXME or maybe s3c2400_gpio_getirq() ... */
> > +#define gpio_to_irq(gpio) s3c2410_gpio_getirq(gpio)
>
> imho, this should be fixed even if the s3c2400 is not 100% supported in
> mainline.
Ok. Could anybody knowledgeable provide an irq_to_gpio function?
regards
Philipp
Index: linux-2.6/include/asm-arm/arch-s3c2410/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-arm/arch-s3c2410/gpio.h 2006-12-21
13:25:44.000000000 +0100
@@ -0,0 +1,65 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * S3C2410 GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_S3C2410_GPIO_H
+#define __ASM_ARCH_S3C2410_GPIO_H
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_INPUT);
+ return 0;
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_OUTPUT);
+ return 0;
+}
+
+#define gpio_get_value(gpio) s3c2410_gpio_getpin(gpio)
+#define gpio_set_value(gpio,value) s3c2410_gpio_setpin(gpio, value)
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+#ifdef CONFIG_CPU_S3C2400
+#define gpio_to_irq(gpio) s3c2400_gpio_getirq(gpio)
+#else
+#define gpio_to_irq(gpio) s3c2410_gpio_getirq(gpio)
+#endif /* CONFIG_CPU_S3C2400 */
+
+/* FIXME implement irq_to_gpio() */
+
+#endif
On Thu, 21 Dec 2006, pHilipp Zabel wrote:
> David suggested to have both inline and non-inline functions depending
> on whether gpio is constant. How is this patch?
More comments below.
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6/include/asm-arm/arch-pxa/gpio.h 2006-12-21
> 07:57:12.000000000 +0100
> @@ -0,0 +1,86 @@
[...]
> +static inline int gpio_direction_input(unsigned gpio)
> +{
> + if (gpio > PXA_LAST_GPIO)
> + return -EINVAL;
> + pxa_gpio_mode(gpio | GPIO_IN);
> +}
> +
> +static inline int gpio_direction_output(unsigned gpio)
> +{
> + if (gpio > PXA_LAST_GPIO)
> + return -EINVAL;
> + pxa_gpio_mode(gpio | GPIO_OUT);
> +}
Please push this test against PXA_LAST_GPIO inside pxa_gpio_mode(). It
has no advantage to be inline if you're about to call a function anyway.
That would make pxa_gpio_mode() more reliable for those not calling it
through the generic API wrt that kind of error as well.
> --- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-16
> +++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-16 16:47:45.000000000
> @@ -129,6 +129,29 @@
> EXPORT_SYMBOL(pxa_gpio_mode);
>
> /*
> + * Return GPIO level, nonzero means high, zero is low
> + */
> +int pxa_gpio_get_value(unsigned gpio)
> +{
> + return GPLR(gpio) & GPIO_bit(gpio);
> +}
> +
> +EXPORT_SYMBOL(pxa_gpio_get_value);
> +
> +/*
> + * Set output GPIO level
> + */
> +void pxa_gpio_set_value(unsigned gpio, int value)
> +{
> + if (value)
> + GPSR(gpio) = GPIO_bit(gpio);
> + else
> + GPCR(gpio) = GPIO_bit(gpio);
> +}
> +
> +EXPORT_SYMBOL(pxa_gpio_set_value);
Instead of duplicating code here, you probably should just reuse
__gpio_set_value() and __gpio_get_value() inside those functions.
Nicolas
On Thursday 21 December 2006 7:03 am, pHilipp Zabel wrote:
> On 12/21/06, Nicolas Pitre <[email protected]> wrote:
> +static inline void __gpio_set_value(unsigned gpio, int value)
> +{
> + if (value)
> + GPSR(gpio) = GPIO_bit(gpio);
> + else
> + GPCR(gpio) = GPIO_bit(gpio);
> +}
> +
> +#define gpio_set_value(gpio,value) \
> + (__builtin_constant_p(gpio) ? \
Should that be testing for _both_ gpio and value being constant?
I tend to think it should (assuming nonconstant 'variable' means
this costs more than a function call) ...
> + __gpio_set_value(gpio, value) : \
> + pxa_gpio_set_value(gpio, value))
On 12/21/06, Nicolas Pitre <[email protected]> wrote:
> On Thu, 21 Dec 2006, pHilipp Zabel wrote:
>
> > David suggested to have both inline and non-inline functions depending
> > on whether gpio is constant. How is this patch?
>
> More comments below.
>
> > --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> > +++ linux-2.6/include/asm-arm/arch-pxa/gpio.h 2006-12-21
> > 07:57:12.000000000 +0100
> > @@ -0,0 +1,86 @@
> [...]
> > +static inline int gpio_direction_input(unsigned gpio)
> > +{
> > + if (gpio > PXA_LAST_GPIO)
> > + return -EINVAL;
> > + pxa_gpio_mode(gpio | GPIO_IN);
> > +}
> > +
> > +static inline int gpio_direction_output(unsigned gpio)
> > +{
> > + if (gpio > PXA_LAST_GPIO)
> > + return -EINVAL;
> > + pxa_gpio_mode(gpio | GPIO_OUT);
> > +}
>
> Please push this test against PXA_LAST_GPIO inside pxa_gpio_mode(). It
> has no advantage to be inline if you're about to call a function anyway.
> That would make pxa_gpio_mode() more reliable for those not calling it
> through the generic API wrt that kind of error as well.
I see. Originally I didn't want to touch generic.c at all.
Now pxa_gpio_mode returns int instead of void.
> > --- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-16
> > +++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-16 16:47:45.000000000
> > @@ -129,6 +129,29 @@
> > EXPORT_SYMBOL(pxa_gpio_mode);
> >
> > /*
> > + * Return GPIO level, nonzero means high, zero is low
> > + */
> > +int pxa_gpio_get_value(unsigned gpio)
> > +{
> > + return GPLR(gpio) & GPIO_bit(gpio);
> > +}
> > +
> > +EXPORT_SYMBOL(pxa_gpio_get_value);
> > +
> > +/*
> > + * Set output GPIO level
> > + */
> > +void pxa_gpio_set_value(unsigned gpio, int value)
> > +{
> > + if (value)
> > + GPSR(gpio) = GPIO_bit(gpio);
> > + else
> > + GPCR(gpio) = GPIO_bit(gpio);
> > +}
> > +
> > +EXPORT_SYMBOL(pxa_gpio_set_value);
>
> Instead of duplicating code here, you probably should just reuse
> __gpio_set_value() and __gpio_get_value() inside those functions.
Probably? What I am wondering is this: can the compiler
optimize away the range check that is duplicated in GPSR/GPCR
and GPIO_bit for __gpio_set/get_value? Or could we optimize
this case by expanding the macros in place (which would mean
duplicating code from pxa-regs.h)...
regards
Philipp
Index: linux-2.6/include/asm-arm/arch-pxa/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-arm/arch-pxa/gpio.h 2006-12-21
20:07:48.000000000 +0100
@@ -0,0 +1,82 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * PXA GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_PXA_GPIO_H
+#define __ASM_ARCH_PXA_GPIO_H
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ return pxa_gpio_mode(gpio | GPIO_IN);
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ return pxa_gpio_mode(gpio | GPIO_OUT);
+}
+
+static inline int __gpio_get_value(unsigned gpio)
+{
+ return GPLR(gpio) & GPIO_bit(gpio);
+}
+
+#define gpio_get_value(gpio) \
+ (__builtin_constant_p(gpio) ? \
+ __gpioe_get_value(gpio) : \
+ pxa_gpio_get_value(gpio))
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR(gpio) = GPIO_bit(gpio);
+ else
+ GPCR(gpio) = GPIO_bit(gpio);
+}
+
+#define gpio_set_value(gpio,value) \
+ (__builtin_constant_p(gpio) ? \
+ __gpio_set_value(gpio, value) : \
+ pxa_gpio_set_value(gpio, value))
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
+#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
+
+
+#endif
Index: linux-2.6/arch/arm/mach-pxa/generic.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-21
13:30:01.000000000 +0100
+++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-21 20:06:16.000000000 +0100
@@ -36,6 +36,7 @@
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/udc.h>
#include <asm/arch/pxafb.h>
#include <asm/arch/serial.h>
@@ -105,13 +106,16 @@
* Handy function to set GPIO alternate functions
*/
-void pxa_gpio_mode(int gpio_mode)
+int pxa_gpio_mode(int gpio_mode)
{
unsigned long flags;
int gpio = gpio_mode & GPIO_MD_MASK_NR;
int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
int gafr;
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+
local_irq_save(flags);
if (gpio_mode & GPIO_DFLT_LOW)
GPCR(gpio) = GPIO_bit(gpio);
@@ -124,11 +128,33 @@
gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
local_irq_restore(flags);
+
+ return 0;
}
EXPORT_SYMBOL(pxa_gpio_mode);
/*
+ * Return GPIO level
+ */
+int pxa_gpio_get_value(unsigned gpio)
+{
+ __gpio_get_value(gpio);
+}
+
+EXPORT_SYMBOL(pxa_gpio_get_value);
+
+/*
+ * Set output GPIO level
+ */
+void pxa_gpio_set_value(unsigned gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+EXPORT_SYMBOL(pxa_gpio_set_value);
+
+/*
* Routine to safely enable or disable a clock in the CKEN
*/
void pxa_set_cken(int clock, int enable)
Index: linux-2.6/include/asm-arm/arch-pxa/hardware.h
===================================================================
--- linux-2.6.orig/include/asm-arm/arch-pxa/hardware.h 2006-12-21
13:30:01.000000000 +0100
+++ linux-2.6/include/asm-arm/arch-pxa/hardware.h 2006-12-21
20:03:55.000000000 +0100
@@ -65,7 +65,17 @@
/*
* Handy routine to set GPIO alternate functions
*/
-extern void pxa_gpio_mode( int gpio_mode );
+extern int pxa_gpio_mode( int gpio_mode );
+
+/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+extern int pxa_gpio_get_value(unsigned gpio);
+
+/*
+ * Set output GPIO level
+ */
+extern void pxa_gpio_set_value(unsigned gpio, int value);
/*
* Routine to enable or disable CKEN
On Thu, 21 Dec 2006, pHilipp Zabel wrote:
> > > --- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-16
> > > +++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-16
> > > 16:47:45.000000000
> > > @@ -129,6 +129,29 @@
> > > EXPORT_SYMBOL(pxa_gpio_mode);
> > >
> > > /*
> > > + * Return GPIO level, nonzero means high, zero is low
> > > + */
> > > +int pxa_gpio_get_value(unsigned gpio)
> > > +{
> > > + return GPLR(gpio) & GPIO_bit(gpio);
> > > +}
> > > +
> > > +EXPORT_SYMBOL(pxa_gpio_get_value);
> > > +
> > > +/*
> > > + * Set output GPIO level
> > > + */
> > > +void pxa_gpio_set_value(unsigned gpio, int value)
> > > +{
> > > + if (value)
> > > + GPSR(gpio) = GPIO_bit(gpio);
> > > + else
> > > + GPCR(gpio) = GPIO_bit(gpio);
> > > +}
> > > +
> > > +EXPORT_SYMBOL(pxa_gpio_set_value);
> >
> > Instead of duplicating code here, you probably should just reuse
> > __gpio_set_value() and __gpio_get_value() inside those functions.
>
> Probably? What I am wondering is this: can the compiler
> optimize away the range check that is duplicated in GPSR/GPCR
> and GPIO_bit for __gpio_set/get_value? Or could we optimize
> this case by expanding the macros in place (which would mean
> duplicating code from pxa-regs.h)...
Sorry I don't quite follow you here. Why would you expand the macro in
place?
My suggestion is only about not duplicating the source code. The
generated assembly will be the same.
And your patch looks fine to me now, except for this:
+int pxa_gpio_get_value(unsigned gpio)
+{
+ __gpio_get_value(gpio);
+}
You certainly meant to add a "return" in there, right?
Nicolas
Guys:
>>Probably? What I am wondering is this: can the compiler
>>optimize away the range check that is duplicated in GPSR/GPCR
>>and GPIO_bit for __gpio_set/get_value? Or could we optimize
>>this case by expanding the macros in place (which would mean
>>duplicating code from pxa-regs.h)...
>>
>>
Who cares? :)
I don't think there's much point in optimizing here, since these
functions won't be hot paths anyway. Yes, they'll be called in
interrupt handlers and so we don't want them to be _too_ heavy, but
compared to the overhead of an interrupt handler, a few extra
instructions in the GPIO access will get lost in the noise.
Inlines generally seem to be more maintainable, give you a symbol that
you can disassemble and breakpoint, etc. I'll take them over the macro
implementations any day, in this case even if there's a cost of a few
instructions.
All IMHO, of course.
b.g.
--
Bill Gatliff
[email protected]
On 12/21/06, Nicolas Pitre <[email protected]> wrote:
> On Thu, 21 Dec 2006, pHilipp Zabel wrote:
>
> > > > --- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-16
> > > > +++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-16
> > > > 16:47:45.000000000
> > > > @@ -129,6 +129,29 @@
> > > > EXPORT_SYMBOL(pxa_gpio_mode);
> > > >
> > > > /*
> > > > + * Return GPIO level, nonzero means high, zero is low
> > > > + */
> > > > +int pxa_gpio_get_value(unsigned gpio)
> > > > +{
> > > > + return GPLR(gpio) & GPIO_bit(gpio);
> > > > +}
> > > > +
> > > > +EXPORT_SYMBOL(pxa_gpio_get_value);
> > > > +
> > > > +/*
> > > > + * Set output GPIO level
> > > > + */
> > > > +void pxa_gpio_set_value(unsigned gpio, int value)
> > > > +{
> > > > + if (value)
> > > > + GPSR(gpio) = GPIO_bit(gpio);
> > > > + else
> > > > + GPCR(gpio) = GPIO_bit(gpio);
> > > > +}
> > > > +
> > > > +EXPORT_SYMBOL(pxa_gpio_set_value);
> > >
> > > Instead of duplicating code here, you probably should just reuse
> > > __gpio_set_value() and __gpio_get_value() inside those functions.
> >
> > Probably? What I am wondering is this: can the compiler
> > optimize away the range check that is duplicated in GPSR/GPCR
> > and GPIO_bit for __gpio_set/get_value? Or could we optimize
> > this case by expanding the macros in place (which would mean
> > duplicating code from pxa-regs.h)...
>
> Sorry I don't quite follow you here. Why would you expand the macro in
> place?
And that is no surprise because I seem to have problems to follow
myself here now after a good night's rest. Basically I was thinking
that after expanding the macros in place the code could be optimized.
Of course, this doesn't have any advantage for the inlined functions
(gpio is constant, so most of the code will be optimized away anyway),
and shaving one or two words off pxa_gpio_setval is hardly worthwile.
> My suggestion is only about not duplicating the source code. The
> generated assembly will be the same.
>
> And your patch looks fine to me now, except for this:
>
> +int pxa_gpio_get_value(unsigned gpio)
> +{
> + __gpio_get_value(gpio);
> +}
>
> You certainly meant to add a "return" in there, right?
Oh yes. Sorry.
cheers
Philipp
Index: linux-2.6/include/asm-arm/arch-pxa/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-arm/arch-pxa/gpio.h 2006-12-21
20:07:48.000000000 +0100
@@ -0,0 +1,82 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * PXA GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_PXA_GPIO_H
+#define __ASM_ARCH_PXA_GPIO_H
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ return pxa_gpio_mode(gpio | GPIO_IN);
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ return pxa_gpio_mode(gpio | GPIO_OUT);
+}
+
+static inline int __gpio_get_value(unsigned gpio)
+{
+ return GPLR(gpio) & GPIO_bit(gpio);
+}
+
+#define gpio_get_value(gpio) \
+ (__builtin_constant_p(gpio) ? \
+ __gpioe_get_value(gpio) : \
+ pxa_gpio_get_value(gpio))
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR(gpio) = GPIO_bit(gpio);
+ else
+ GPCR(gpio) = GPIO_bit(gpio);
+}
+
+#define gpio_set_value(gpio,value) \
+ (__builtin_constant_p(gpio) ? \
+ __gpio_set_value(gpio, value) : \
+ pxa_gpio_set_value(gpio, value))
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
+#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
+
+
+#endif
Index: linux-2.6/arch/arm/mach-pxa/generic.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-21
13:30:01.000000000 +0100
+++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-21 21:25:24.000000000 +0100
@@ -36,6 +36,7 @@
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/udc.h>
#include <asm/arch/pxafb.h>
#include <asm/arch/serial.h>
@@ -105,13 +106,16 @@
* Handy function to set GPIO alternate functions
*/
-void pxa_gpio_mode(int gpio_mode)
+int pxa_gpio_mode(int gpio_mode)
{
unsigned long flags;
int gpio = gpio_mode & GPIO_MD_MASK_NR;
int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
int gafr;
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+
local_irq_save(flags);
if (gpio_mode & GPIO_DFLT_LOW)
GPCR(gpio) = GPIO_bit(gpio);
@@ -124,11 +128,33 @@
gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
local_irq_restore(flags);
+
+ return 0;
}
EXPORT_SYMBOL(pxa_gpio_mode);
/*
+ * Return GPIO level
+ */
+int pxa_gpio_get_value(unsigned gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+EXPORT_SYMBOL(pxa_gpio_get_value);
+
+/*
+ * Set output GPIO level
+ */
+void pxa_gpio_set_value(unsigned gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+EXPORT_SYMBOL(pxa_gpio_set_value);
+
+/*
* Routine to safely enable or disable a clock in the CKEN
*/
void pxa_set_cken(int clock, int enable)
Index: linux-2.6/include/asm-arm/arch-pxa/hardware.h
===================================================================
--- linux-2.6.orig/include/asm-arm/arch-pxa/hardware.h 2006-12-21
13:30:01.000000000 +0100
+++ linux-2.6/include/asm-arm/arch-pxa/hardware.h 2006-12-21
20:03:55.000000000 +0100
@@ -65,7 +65,17 @@
/*
* Handy routine to set GPIO alternate functions
*/
-extern void pxa_gpio_mode( int gpio_mode );
+extern int pxa_gpio_mode( int gpio_mode );
+
+/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+extern int pxa_gpio_get_value(unsigned gpio);
+
+/*
+ * Set output GPIO level
+ */
+extern void pxa_gpio_set_value(unsigned gpio, int value);
/*
* Routine to enable or disable CKEN
On 12/21/06, Andrew Morton <[email protected]> wrote:
> On Wed, 20 Dec 2006 13:13:21 -0800
> David Brownell <[email protected]> wrote:
>
> > +#define gpio_get_value(gpio) \
> > + (GPLR & GPIO_GPIO(gpio))
> > +
> > +#define gpio_set_value(gpio,value) \
> > + ((value) ? (GPSR = GPIO_GPIO(gpio)) : (GPCR(gpio) = GPIO_GPIO(gpio)))
>
> likewise.
I have done the same to the SA1100 wrappers as to the PXA wrappers now.
Maybe the non-inline functions in generic.c are overkill for those much simpler
macros on SA...
regards
Philipp
Index: linux-2.6/include/asm-arm/arch-sa1100/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-arm/arch-sa1100/gpio.h 2006-12-22
08:07:08.000000000 +0100
@@ -0,0 +1,95 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * SA1100 GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_SA1100_GPIO_H
+#define __ASM_ARCH_SA1100_GPIO_H
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/errno.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ if (gpio > GPIO_MAX)
+ return -EINVAL;
+ GPDR = (GPDR_In << gpio);
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ if (gpio > GPIO_MAX)
+ return -EINVAL;
+ GPDR = (GPDR_Out << gpio);
+}
+
+static inline int __gpio_get_value(unsigned gpio)
+{
+ return GPLR & GPIO_GPIO(gpio);
+}
+
+#define gpio_get_value(gpio) \
+ (__builtin_constant_p(gpio) ? \
+ __gpioe_get_value(gpio) : \
+ sa1100_gpio_get_value(gpio))
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR = GPIO_GPIO(gpio);
+ else
+ GPCR = GPIO_GPIO(gpio);
+}
+
+#define gpio_set_value(gpio,value) \
+ (__builtin_constant_p(gpio) ? \
+ __gpio_set_value(gpio, value) : \
+ sa1100_gpio_set_value(gpio, value))
+
+static inline unsigned gpio_to_irq(unsigned gpio)
+{
+ if (gpio < 11)
+ return IRQ_GPIO0 + gpio;
+ else
+ return IRQ_GPIO11 - 11 + gpio;
+}
+
+static inline unsigned irq_to_gpio(unsigned irq)
+{
+ if (irq < IRQ_GPIO11_27)
+ return irq - IRQ_GPIO0;
+ else
+ return irq - IRQ_GPIO11 + 11;
+}
+
+#endif
Index: linux-2.6/arch/arm/mach-sa1100/generic.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-sa1100/generic.c 2006-12-22
07:57:46.000000000 +0100
+++ linux-2.6/arch/arm/mach-sa1100/generic.c 2006-12-22 08:12:51.000000000 +0100
@@ -28,6 +28,8 @@
#include <asm/mach/flash.h>
#include <asm/irq.h>
+#include <asm/arch/gpio.h>
+
#include "generic.h"
#define NR_FREQS 16
@@ -139,6 +141,26 @@
}
/*
+ * Return GPIO level
+ */
+int sa1100_gpio_get_value(unsigned gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+EXPORT_SYMBOL(sa1100_gpio_get_value);
+
+/*
+ * Set output GPIO level
+ */
+void sa1100_gpio_set_value(unsigned gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+EXPORT_SYMBOL(sa1100_gpio_set_value);
+
+/*
* Default power-off for SA1100
*/
static void sa1100_power_off(void)
Index: linux-2.6/include/asm-arm/arch-sa1100/hardware.h
===================================================================
--- linux-2.6.orig/include/asm-arm/arch-sa1100/hardware.h 2006-12-22
07:58:13.000000000 +0100
+++ linux-2.6/include/asm-arm/arch-sa1100/hardware.h 2006-12-22
08:02:23.000000000 +0100
@@ -48,6 +48,16 @@
#endif
+/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+extern int sa1100_gpio_get_value(unsigned gpio);
+
+/*
+ * Set output GPIO level
+ */
+void sa1100_gpio_set_value(unsigned gpio, int value);
+
#include "SA-1100.h"
#ifdef CONFIG_SA1101
On Fri, 22 Dec 2006, pHilipp Zabel wrote:
> On 12/21/06, Andrew Morton <[email protected]> wrote:
> > On Wed, 20 Dec 2006 13:13:21 -0800
> > David Brownell <[email protected]> wrote:
> >
> > > +#define gpio_get_value(gpio) \
> > > + (GPLR & GPIO_GPIO(gpio))
> > > +
> > > +#define gpio_set_value(gpio,value) \
> > > + ((value) ? (GPSR = GPIO_GPIO(gpio)) : (GPCR(gpio) =
> > > GPIO_GPIO(gpio)))
> >
> > likewise.
>
> I have done the same to the SA1100 wrappers as to the PXA wrappers now.
> Maybe the non-inline functions in generic.c are overkill for those much
> simpler
> macros on SA...
I think the SA1x00 has no advantage of having out of line versions. The
function call will cost more than the inline version even if gpio is not
constant.
Nicolas
On Wed, Dec 20, 2006 at 01:13:21PM -0800, David Brownell wrote:
> Arch-neutral GPIO calls for SA-1100.
>
> From: Philipp Zabel <[email protected]>
>
> +static inline unsigned gpio_to_irq(unsigned gpio)
> +{
> + if (gpio < 11)
> + return IRQ_GPIO0 + gpio;
> + else
> + return IRQ_GPIO11 - 11 + gpio;
> +}
> +
> +static inline unsigned irq_to_gpio(unsigned irq)
> +{
> + if (irq < IRQ_GPIO11_27)
> + return irq - IRQ_GPIO0;
> + else
> + return irq - IRQ_GPIO11 + 11;
> +}
Why do we need to convert between IRQ and PGIO numbers? This is NOT
something that drivers should even care about - it's something that the
interrupt subsystem should know when being asked to claim an GPIO-based
IRQ.
That's something I worked hard to eliminate from the SA1100 drivers,
please don't reintroduce this silly idea again.
When the interrupt system is asked to claim a IRQ corresponding to a
GPIO, it should deal with all the stuff necessary to ensure that the
GPIO is in the required state. Drivers should not be considering
converting IRQ numbers to GPIOs or vice versa.
Doing otherwise is just plain silly - are we expecting to add GPIO
support to all Linux drivers which could possibly be used on ARM, just
because their interrupt pin might possibly be connected to a GPIO?
Get real - if you're dealing with IRQs use _only_ IRQ numbers. Don't
even think that drivers should be able to convert between IRQ and GPIO
numbers.
--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:
On Thu, Dec 21, 2006 at 11:33:11AM +0100, Arnaud Patard wrote:
> > +#include <asm/arch/irqs.h>
>
> imho, this is not needed. The user who will use irq will add it in his
> code anyway.
>
> > +#include <asm/arch/hardware.h>
This is a pet peave. _NO_ drivers should include either of these two
headers directly. Use asm/irq.h and asm/hardware.h instead. Audit your
code to ensure that you're including the right headers please.
I can see that I've got to do another sweep of the entire kernel code
to fix all these again.
--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:
On Saturday 23 December 2006 3:37 am, Russell King wrote:
> Why do we need to convert between IRQ and PGIO numbers?
(I take it that's the only real issue you had with this patch, other
than maybe excessive #includes?)
I suppose we could do with a one way mapping: GPIO-to-IRQ, then
require drivers map the other way themselves when they need to.
As they must do with DMA addresses.
Having that GPIO-to-IRQ mapping is quite routine; and necessary.
On the other hand, since it's a (small) one-to-one mapping, I don't
see any real issue with defining how to access it in both directions.
I can tell one direction (IRQ-to-GPIO) bothers you ... but not why.
> When the interrupt system is asked to claim a IRQ corresponding to a
> GPIO, it should deal with all the stuff necessary to ensure that the
> GPIO is in the required state.
IRQ framework can't do "all" the needed stuff on platforms (like OMAP1)
where knowing the GPIO (presumably from a private IRQ-to-GPIO mapping??)
doesn't tell you what pin to set up, or how. Such setup needs to be in
place *before* request_irq() is called. The genirq irqchip.startup()
call could potentially sanity check whether a GPIO is configured as an
input, but couldn't handle pin muxing or pullup/pulldown config; and
I'd argue it shouldn't try to change anyt of that, since it's an API
for managing IRQs not for pin configuration.
> are we expecting to add GPIO
> support to all Linux drivers which could possibly be used on ARM, just
> because their interrupt pin might possibly be connected to a GPIO?
I'd expect board-specific setup code to pass gpio_to_irq(gpio_num) to
drivers when the _only_ thing that matters is its IRQ-ness. And to
have previousy set up the relevant pin as a GPIO input ... so that most
drivers would just see an IRQ, much like any other irq.
That's what most of them do now, I didn't propose changing any part of
that except defining a standard way to write the GPIO-to-IRQ mapping.
The overall goal is basically to let drivers which know they've got a
GPIO have a standard way to use it ... in the previous situation, the
lack of such a portable API means those drivers must be (needlessly)
platform-specific.
> This is NOT
> something that drivers should even care about - it's something that the
> interrupt subsystem should know when being asked to claim an GPIO-based
> IRQ.
It's admittedly uncommon that drivers care about IRQ-to-GPIO, but it's
not a "never" thing. Drivers often need to care more about the exact
state of the signal than "IRQ triggered a while back"; and that means
some kind of IRQ-to-GPIO mapping.
Examples: systems that only have "both edges" triggering, where the
hardware signal is level triggered; or the supported triggering modes
are otherwise not a good match for an external chip. State when the
driver starts up may need to check signal level directly, when the
IRQ must use edge triggering. Also, disabling an IRQ at the source
(vs. unsharably masking it in the local IRQ controller) can sometimes
take much of a millisecond because of I2C or similar delays, making
it likely that signal state changed since the irq triggered. Oh, and
the reverse mapping could also be useful for diagnostics.
> Get real - if you're dealing with IRQs use _only_ IRQ numbers. Don't
> even think that drivers should be able to convert between IRQ and GPIO
> numbers.
I was being real, and I gave some examples above where drivers need to
be able to detect the actual signal level.
On the other hand it'd also be practical to force drivers to do that
mapping from IRQ (they probably only handle a few!) to GPIO, when they
need to do that, if they're given a GPIO number directly. Then they'd
just use the GPIO-to-IRQ mapping to request the IRQ (already a common
idiom) and directly access the gpio state.
- Dave
Hi!
> +Identifying GPIOs
> +-----------------
> +GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
> +reserves "negative" numbers for other purposes like marking signals as
> +"not available on this board", or indicating faults.
> +
> +Platforms define how they use those integers, and usually #define symbols
> +for the GPIO lines so that board-specific setup code directly corresponds
> +to the relevant schematics. In contrast, drivers should only use GPIO
Perhaps these should not be integers, then?
typedef struct { int mydata } pin_t; prevents people from looking
inside, allows you to typecheck, and allows expansion in (unlikely) case where
more than int is needed? ...hotpluggable gpio pins?
> +Spinlock-Safe GPIO access
> +-------------------------
> +Most GPIO controllers can be accessed with memory read/write instructions.
> +That doesn't need to sleep, and can safely be done from inside IRQ handlers.
> +
> +Use these calls to access such GPIOs:
> +
> + /* GPIO INPUT: return zero or nonzero */
> + int gpio_get_value(unsigned gpio);
> +
> + /* GPIO OUTPUT */
> + void gpio_set_value(unsigned gpio, int value);
> +
> +The values are boolean, zero for low, nonzero for high. When reading the
> +value of an output pin, the value returned should be what's seen on the
> +pin ... that won't always match the specified output value, because of
> +issues including wire-OR and output latencies.
> +
> +The get/set calls have no error returns because "invalid GPIO" should have
> +been reported earlier in gpio_set_direction(). However, note that not all
> +platforms can read the value of output pins; those that can't should always
> +return zero.
> Also, these calls will be ignored for GPIOs that can't safely
> +be accessed wihtout sleeping (see below).
'Silently ignored' is ugly. BUG() would be okay there.
> +Platforms that support this type of GPIO distinguish them from other GPIOs
> +by returning nonzero from this call:
> +
> + int gpio_cansleep(unsigned gpio);
This is ugly :-(. But I don't see easy way around...
> +GPIOs mapped to IRQs
> +--------------------
> +GPIO numbers are unsigned integers; so are IRQ numbers. These make up
> +two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can
> +map between them using calls like:
> +
> + /* map GPIO numbers to IRQ numbers */
> + int gpio_to_irq(unsigned gpio);
> +
> + /* map IRQ numbers to GPIO numbers */
> + int irq_to_gpio(unsigned irq);
. Don't we have irq_t already?
> +Those return either the corresponding number in the other namespace, or
> +else a negative errno code if the mapping can't be done. (For example,
> +some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
> +number that hasn't been marked as an input using gpio_set_direction(), or
It should be valid to do irqs on outputs, if those outputs are really
tristates (wire-or or how you call it?)?
Pavel
--
Thanks for all the (sleeping) penguins.
Hi!
> Arch-neutral GPIO calls for PXA.
>
> From: Philipp Zabel <[email protected]>
Missing s-o-b?
> +static inline int gpio_direction_input(unsigned gpio)
> +{
> + if (gpio > PXA_LAST_GPIO)
> + return -EINVAL;
> + pxa_gpio_mode(gpio | GPIO_IN);
> +}
Missing return 0?
> +static inline int gpio_direction_output(unsigned gpio)
> +{
> + if (gpio > PXA_LAST_GPIO)
> + return -EINVAL;
> + pxa_gpio_mode(gpio | GPIO_OUT);
> +}
> +
And here?
Pavel
--
Thanks for all the (sleeping) penguins.
Hi!
> +static inline int gpio_direction_input(unsigned gpio)
> +{
> + if (gpio > GPIO_MAX)
> + return -EINVAL;
> + GPDR = (GPDR_In << gpio) 0
> +}
Missing return 0.
> +static inline int gpio_direction_output(unsigned gpio)
> +{
> + if (gpio > GPIO_MAX)
> + return -EINVAL;
> + GPDR = (GPDR_Out << gpio) 0
> +}
Here too.
--
Thanks for all the (sleeping) penguins.
Phillip: is this the final version, then? It's missing
a signed-off-by line, so I can't do anything appropriate.
Nico, your signoff here would be a Good Thing too if it
meets your technical review. (My only comment, ISTR, was
that gpio_set_value macro should probably test for whether
the value is a constant too, not just the gpio pin.)
- Dave
On Thursday 21 December 2006 10:53 pm, pHilipp Zabel wrote:
>
> Index: linux-2.6/include/asm-arm/arch-pxa/gpio.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6/include/asm-arm/arch-pxa/gpio.h 2006-12-21
> 20:07:48.000000000 +0100
> @@ -0,0 +1,82 @@
> +/*
> + * linux/include/asm-arm/arch-pxa/gpio.h
> + *
> + * PXA GPIO wrappers for arch-neutral GPIO calls
> + *
> + * Written by Philipp Zabel <[email protected]>
> + *
> + * 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
> + *
> + */
> +
> +#ifndef __ASM_ARCH_PXA_GPIO_H
> +#define __ASM_ARCH_PXA_GPIO_H
> +
> +#include <asm/arch/pxa-regs.h>
> +#include <asm/arch/irqs.h>
> +#include <asm/arch/hardware.h>
> +
> +#include <asm/errno.h>
> +
> +static inline int gpio_request(unsigned gpio, const char *label)
> +{
> + return 0;
> +}
> +
> +static inline void gpio_free(unsigned gpio)
> +{
> + return;
> +}
> +
> +static inline int gpio_direction_input(unsigned gpio)
> +{
> + return pxa_gpio_mode(gpio | GPIO_IN);
> +}
> +
> +static inline int gpio_direction_output(unsigned gpio)
> +{
> + return pxa_gpio_mode(gpio | GPIO_OUT);
> +}
> +
> +static inline int __gpio_get_value(unsigned gpio)
> +{
> + return GPLR(gpio) & GPIO_bit(gpio);
> +}
> +
> +#define gpio_get_value(gpio) \
> + (__builtin_constant_p(gpio) ? \
> + __gpioe_get_value(gpio) : \
> + pxa_gpio_get_value(gpio))
> +
> +static inline void __gpio_set_value(unsigned gpio, int value)
> +{
> + if (value)
> + GPSR(gpio) = GPIO_bit(gpio);
> + else
> + GPCR(gpio) = GPIO_bit(gpio);
> +}
> +
> +#define gpio_set_value(gpio,value) \
> + (__builtin_constant_p(gpio) ? \
> + __gpio_set_value(gpio, value) : \
> + pxa_gpio_set_value(gpio, value))
> +
> +#include <asm-generic/gpio.h> /* cansleep wrappers */
> +
> +#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
> +#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
> +
> +
> +#endif
> Index: linux-2.6/arch/arm/mach-pxa/generic.c
> ===================================================================
> --- linux-2.6.orig/arch/arm/mach-pxa/generic.c 2006-12-21
> 13:30:01.000000000 +0100
> +++ linux-2.6/arch/arm/mach-pxa/generic.c 2006-12-21 21:25:24.000000000 +0100
> @@ -36,6 +36,7 @@
> #include <asm/mach/map.h>
>
> #include <asm/arch/pxa-regs.h>
> +#include <asm/arch/gpio.h>
> #include <asm/arch/udc.h>
> #include <asm/arch/pxafb.h>
> #include <asm/arch/serial.h>
> @@ -105,13 +106,16 @@
> * Handy function to set GPIO alternate functions
> */
>
> -void pxa_gpio_mode(int gpio_mode)
> +int pxa_gpio_mode(int gpio_mode)
> {
> unsigned long flags;
> int gpio = gpio_mode & GPIO_MD_MASK_NR;
> int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
> int gafr;
>
> + if (gpio > PXA_LAST_GPIO)
> + return -EINVAL;
> +
> local_irq_save(flags);
> if (gpio_mode & GPIO_DFLT_LOW)
> GPCR(gpio) = GPIO_bit(gpio);
> @@ -124,11 +128,33 @@
> gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
> GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
> local_irq_restore(flags);
> +
> + return 0;
> }
>
> EXPORT_SYMBOL(pxa_gpio_mode);
>
> /*
> + * Return GPIO level
> + */
> +int pxa_gpio_get_value(unsigned gpio)
> +{
> + return __gpio_get_value(gpio);
> +}
> +
> +EXPORT_SYMBOL(pxa_gpio_get_value);
> +
> +/*
> + * Set output GPIO level
> + */
> +void pxa_gpio_set_value(unsigned gpio, int value)
> +{
> + __gpio_set_value(gpio, value);
> +}
> +
> +EXPORT_SYMBOL(pxa_gpio_set_value);
> +
> +/*
> * Routine to safely enable or disable a clock in the CKEN
> */
> void pxa_set_cken(int clock, int enable)
> Index: linux-2.6/include/asm-arm/arch-pxa/hardware.h
> ===================================================================
> --- linux-2.6.orig/include/asm-arm/arch-pxa/hardware.h 2006-12-21
> 13:30:01.000000000 +0100
> +++ linux-2.6/include/asm-arm/arch-pxa/hardware.h 2006-12-21
> 20:03:55.000000000 +0100
> @@ -65,7 +65,17 @@
> /*
> * Handy routine to set GPIO alternate functions
> */
> -extern void pxa_gpio_mode( int gpio_mode );
> +extern int pxa_gpio_mode( int gpio_mode );
> +
> +/*
> + * Return GPIO level, nonzero means high, zero is low
> + */
> +extern int pxa_gpio_get_value(unsigned gpio);
> +
> +/*
> + * Set output GPIO level
> + */
> +extern void pxa_gpio_set_value(unsigned gpio, int value);
>
> /*
> * Routine to enable or disable CKEN
>
On Wednesday 27 December 2006 9:53 am, Pavel Machek wrote:
> Hi!
>
> > Arch-neutral GPIO calls for PXA.
> >
> > From: Philipp Zabel <[email protected]>
>
> Missing s-o-b?
Yes, still ...
> > +static inline int gpio_direction_input(unsigned gpio)
> > +{
> > + if (gpio > PXA_LAST_GPIO)
> > + return -EINVAL;
> > + pxa_gpio_mode(gpio | GPIO_IN);
> > +}
>
> Missing return 0?
>
> > +static inline int gpio_direction_output(unsigned gpio)
> > +{
> > + if (gpio > PXA_LAST_GPIO)
> > + return -EINVAL;
> > + pxa_gpio_mode(gpio | GPIO_OUT);
> > +}
> > +
>
> And here?
You're looking at about the oldest version of that patch.
Admittedly there were too many floating around...
Hi!
> > > From: Philipp Zabel <[email protected]>
> >
> > Missing s-o-b?
>
> Yes, still ...
>
> > > +static inline int gpio_direction_input(unsigned gpio)
> > > +{
> > > + if (gpio > PXA_LAST_GPIO)
> > > + return -EINVAL;
> > > + pxa_gpio_mode(gpio | GPIO_IN);
> > > +}
> >
> > Missing return 0?
> >
> > > +static inline int gpio_direction_output(unsigned gpio)
> > > +{
> > > + if (gpio > PXA_LAST_GPIO)
> > > + return -EINVAL;
> > > + pxa_gpio_mode(gpio | GPIO_OUT);
> > > +}
> > > +
> >
> > And here?
>
> You're looking at about the oldest version of that patch.
> Admittedly there were too many floating around...
I think I've looked at the newer ones, too, and this particular return
was _not_ fixed.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Thu 2006-12-28 21:50:55, Pavel Machek wrote:
> Hi!
>
> > > > From: Philipp Zabel <[email protected]>
> > >
> > > Missing s-o-b?
> >
> > Yes, still ...
> >
> > > > +static inline int gpio_direction_input(unsigned gpio)
> > > > +{
> > > > + if (gpio > PXA_LAST_GPIO)
> > > > + return -EINVAL;
> > > > + pxa_gpio_mode(gpio | GPIO_IN);
> > > > +}
> > >
> > > Missing return 0?
> > >
> > > > +static inline int gpio_direction_output(unsigned gpio)
> > > > +{
> > > > + if (gpio > PXA_LAST_GPIO)
> > > > + return -EINVAL;
> > > > + pxa_gpio_mode(gpio | GPIO_OUT);
> > > > +}
> > > > +
> > >
> > > And here?
> >
> > You're looking at about the oldest version of that patch.
> > Admittedly there were too many floating around...
>
> I think I've looked at the newer ones, too, and this particular return
> was _not_ fixed.
Ok, I was wrong, the very newest one seems to be okay.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Wednesday 27 December 2006 9:49 am, Pavel Machek wrote:
> Hi!
Good afternoon. :)
> > +Identifying GPIOs
> > +-----------------
> > +GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
> > +reserves "negative" numbers for other purposes like marking signals as
> > +"not available on this board", or indicating faults.
> > +
> > +Platforms define how they use those integers, and usually #define symbols
> > +for the GPIO lines so that board-specific setup code directly corresponds
> > +to the relevant schematics. In contrast, drivers should only use GPIO
>
> Perhaps these should not be integers, then?
Thing is, the platforms **DO** identify them as integers.
Go through OMAP, PXA, StrongARM chip docs ... what you see is
references to GPIO numbers, 0..MAX, and oh by the way those map to
bit offsets within gpio controller banks.
When they don't identify them as integers, as with AT91, AVR32, and
S3C -- all of which present GPIOs as a lettered bank plus a bit offset
within that bank, isn't that structure familiar -- then the Linux
platform support already #defines them as integers. The naming matches
chip docs, the _numbering_ works much the same as on OMAP, PXA, etc.
Fortunately, only OMAP1 seems to have that ugly many-to-many mapping
between chip pins and GPIOs. On other current platforms, once you
know the GPIO number you know the pin, and vice versa. (That does
not matter to drivers at all -- only board setup code talks "pins",
everything else talks about functions such as "GPIO" -- but hairy
board setup code can be a frelling HUGE time sink/waste.)
> typedef struct { int mydata } pin_t; prevents people from looking
> inside, allows you to typecheck, and allows expansion in (unlikely) case where
> more than int is needed? ...hotpluggable gpio pins?
If some system wants that kind of infrastructure, it can easily
implement it behind this API. There's the IDR infrastructure, for
example, to allocate integers and map them to "more than int" data
for internal uses.
I could very easily imagine platforms that support the spinlock-safe
accessors for the SOC-integrated GPIOs, e.g. numbered below N, and
have a more dynamic "plug in your own external GPIO controller" way
to support GPIOs on i2c expanders, multifunction chips, and suchlike;
with that plugin stuff built over IDR and structures with ops vectors.
> > +Spinlock-Safe GPIO access
> > +-------------------------
> > ...
> > +
> > + /* GPIO INPUT: return zero or nonzero */
> > + int gpio_get_value(unsigned gpio);
> > +
> > + /* GPIO OUTPUT */
> > + void gpio_set_value(unsigned gpio, int value);
> > +
> > ...
> > +
> > +The get/set calls have no error returns because "invalid GPIO" should have
> > +been reported earlier in gpio_set_direction(). However, note that not all
> > +platforms can read the value of output pins; those that can't should always
> > +return zero. Also, these calls will be ignored for GPIOs that can't safely
> > +be accessed without sleeping (see below).
>
> 'Silently ignored' is ugly. BUG() would be okay there.
The reason for "silently ignored" is that we really don't want to be
cluttering up the code (source or object) with logic to test for this
kind of "can't happen" failure, especially since there's not going to
be any way to _resolve_ such failures cleanly.
And per Linus' rule about BUG(), "silently ignored" is clearly better
than needlessly stopping the whole system.
And for spinlock-unsafe cases, like I2C based GPIO expanders;
> > +Platforms that support this type of GPIO distinguish them from other GPIOs
> > +by returning nonzero from this call:
> > +
> > + int gpio_cansleep(unsigned gpio);
>
> This is ugly :-(. But I don't see easy way around...
Me either. Folk said earlier they want an API that can get/set
both types of GPIO, mostly to support userspace tweaking/config APIs,
but the only way I can see to have one of those is to include a
predicate like gpio_cansleep() to distinguish the two types.
> > +GPIOs mapped to IRQs
> > +--------------------
> > +GPIO numbers are unsigned integers; so are IRQ numbers. These make up
> > +two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can
> > +map between them using calls like:
> > +
> > + /* map GPIO numbers to IRQ numbers */
> > + int gpio_to_irq(unsigned gpio);
> > +
> > + /* map IRQ numbers to GPIO numbers */
> > + int irq_to_gpio(unsigned irq);
>
> . Don't we have irq_t already?
Nope. Such a type would likely get in the way of lowlevel IRQ
dispatch code too ...
> > +Those return either the corresponding number in the other namespace, or
> > +else a negative errno code if the mapping can't be done. (For example,
> > +some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
> > +number that hasn't been marked as an input using gpio_set_direction(), or
>
> It should be valid to do irqs on outputs,
Good point -- it _might_ be valid to do that, on some platforms.
Such things have been used as a software IRQ trigger, which can
make bootstrapping some things easier.
That's not incompatible with it being an error for portable code to
try that, or with refusing to check it so that those platforms don't
needlessly cause trouble!
If I submit a patch against 2.6.20-rc2-mm1 to address Russell's
dislike of irq_to_gpio() calls (as yet un-explained), I'll try to
remember to mention this platform-specific issue.
> if those outputs are really
> tristates (wire-or or how you call it?)?
That's not tristate. An example of wire-OR would be a signal that
any of three different sources could drive high, but nobody drives
low (except an external pulldown). Contrariwise, and maybe much
more common because it's what I2C does, is a signal that any source
can drive low, but nobody drives high (except one external pullup).
In both cases, drivers can notice an interesting case: the value
they read from the pin doesn't match what they expected, meaning
that some other component is driving the signal.
Those kinds of mechanism support bidirectional I/O on one pin.
Examples include the I2C clock stretch mechanism, and also its
multi-master arbitration; and ISTR card address assignment with
pure MMC (if anyone really uses that in bus mode).
- Dave
> Good afternoon. :)
Good after-midnight :-).
> > > +Identifying GPIOs
> > > +-----------------
> > > +GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
> > > +reserves "negative" numbers for other purposes like marking signals as
> > > +"not available on this board", or indicating faults.
> > > +
> > > +Platforms define how they use those integers, and usually #define symbols
> > > +for the GPIO lines so that board-specific setup code directly corresponds
> > > +to the relevant schematics. In contrast, drivers should only use GPIO
> >
> > Perhaps these should not be integers, then?
>
> Thing is, the platforms **DO** identify them as integers.
> Go through OMAP, PXA, StrongARM chip docs ... what you see is
> references to GPIO numbers, 0..MAX, and oh by the way those map to
> bit offsets within gpio controller banks.
Well. when you see (something) = gpio_number + 5 ... you most likely
have an error. That means that they are close to integers, but not
quite. I'd use
typedef int gpio_t;
...it also serves as a nice documentation.
> When they don't identify them as integers, as with AT91, AVR32, and
> S3C -- all of which present GPIOs as a lettered bank plus a bit offset
> within that bank, isn't that structure familiar -- then the Linux
> platform support already #defines them as integers. The naming matches
Great, except that mechanism should not #define them but "enum gpio {
} " them...
> > inside, allows you to typecheck, and allows expansion in (unlikely) case where
> > more than int is needed? ...hotpluggable gpio pins?
>
> If some system wants that kind of infrastructure, it can easily
> implement it behind this API. There's the IDR infrastructure, for
No, that's a wrong way. I want you to admit that gpio numbers are
opaque cookies noone should look at, and use (something like)
gpio_t... so that we can teach sparse to check them.
> > > +The get/set calls have no error returns because "invalid GPIO" should have
> > > +been reported earlier in gpio_set_direction(). However, note that not all
> > > +platforms can read the value of output pins; those that can't should always
> > > +return zero. Also, these calls will be ignored for GPIOs that can't safely
> > > +be accessed without sleeping (see below).
> >
> > 'Silently ignored' is ugly. BUG() would be okay there.
>
> The reason for "silently ignored" is that we really don't want to be
> cluttering up the code (source or object) with logic to test for this
> kind of "can't happen" failure, especially since there's not going to
> be any way to _resolve_ such failures cleanly.
You may not want to clutter up code for one arch, but for some of them
maybe it is okay and welcome. Please do not document "silently
ignored" into API.
> And per Linus' rule about BUG(), "silently ignored" is clearly better
> than needlessly stopping the whole system.
You are perverting what Linus said. "Do not bother detecting errors"
is not what he had in mind.. but perhaps it should be WARN() not
BUG().
> > > +Those return either the corresponding number in the other namespace, or
> > > +else a negative errno code if the mapping can't be done. (For example,
> > > +some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
> > > +number that hasn't been marked as an input using gpio_set_direction(), or
> >
> > It should be valid to do irqs on outputs,
>
> Good point -- it _might_ be valid to do that, on some platforms.
> Such things have been used as a software IRQ trigger, which can
> make bootstrapping some things easier.
>
> That's not incompatible with it being an error for portable code to
I believe your text suggests it _is_ incompatible. Plus that seems to
mean that architecture must not check for that error...
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Just FYI -- I updated your patch, fixed a compile bug, and switched
some code over to use this new API. The patch is appended.
I happen to think it's a lot easier to read this way. Maybe to some
people it's easy to remember what a GPLR, GPCR, and GPSR register is
supposed to do, after a long time away from PXA or StrongARM platform
code; I'm not one of them.
And on a side note, yes it would make sense for someone to update the
GPIO IRQ support to properly manage PWER, so there's less need for
board-specific PM glue code. :)
- Dave
This is an UNTESTED bunch of conversions of PXA code to use the new GPIO
interfaces, and other build/warning fixes. It's not complete, or even
fully reviewed; but it builds.
Note that the idioms in the API are, as with other architectures, a very
direct match for the existing code ... and so the conversions are easy
to do and to review.
arch/arm/mach-pxa/corgi.c | 13 ++++---------
arch/arm/mach-pxa/corgi_lcd.c | 8 ++++++--
arch/arm/mach-pxa/corgi_pm.c | 25 ++++++++++---------------
arch/arm/mach-pxa/corgi_ssp.c | 18 ++++++++++--------
arch/arm/mach-pxa/sharpsl.h | 6 ------
arch/arm/mach-pxa/spitz_pm.c | 6 +++---
drivers/usb/gadget/pxa2xx_udc.c | 20 ++++++++++++++------
drivers/usb/gadget/pxa2xx_udc.h | 21 ++-------------------
drivers/video/backlight/corgi_bl.c | 2 +-
drivers/video/backlight/locomolcd.c | 3 ++-
10 files changed, 52 insertions(+), 70 deletions(-)
Index: pxa/arch/arm/mach-pxa/corgi.c
===================================================================
--- pxa.orig/arch/arm/mach-pxa/corgi.c 2006-12-10 01:30:42.000000000 -0800
+++ pxa/arch/arm/mach-pxa/corgi.c 2006-12-29 16:44:15.000000000 -0800
@@ -28,6 +28,7 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/gpio.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -239,15 +240,12 @@ static void corgi_mci_setpower(struct de
{
struct pxamci_platform_data* p_d = dev->platform_data;
- if (( 1 << vdd) & p_d->ocr_mask)
- GPSR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
- else
- GPCR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
+ gpio_set_value(CORGI_GPIO_SD_PWR, (1 << vdd) & p_d->ocr_mask);
}
static int corgi_mci_get_ro(struct device *dev)
{
- return GPLR(CORGI_GPIO_nSD_WP) & GPIO_bit(CORGI_GPIO_nSD_WP);
+ return gpio_get_value(CORGI_GPIO_nSD_WP);
}
static void corgi_mci_exit(struct device *dev, void *data)
@@ -269,10 +267,7 @@ static struct pxamci_platform_data corgi
*/
static void corgi_irda_transceiver_mode(struct device *dev, int mode)
{
- if (mode & IR_OFF)
- GPSR(CORGI_GPIO_IR_ON) = GPIO_bit(CORGI_GPIO_IR_ON);
- else
- GPCR(CORGI_GPIO_IR_ON) = GPIO_bit(CORGI_GPIO_IR_ON);
+ gpio_set_value(CORGI_GPIO_IR_ON, mode & IR_OFF);
}
static struct pxaficp_platform_data corgi_ficp_platform_data = {
Index: pxa/drivers/usb/gadget/pxa2xx_udc.h
===================================================================
--- pxa.orig/drivers/usb/gadget/pxa2xx_udc.h 2006-12-10 01:31:53.000000000 -0800
+++ pxa/drivers/usb/gadget/pxa2xx_udc.h 2006-12-29 16:32:41.000000000 -0800
@@ -139,6 +139,8 @@ struct pxa2xx_udc {
struct pxa2xx_ep ep [PXA_UDC_NUM_ENDPOINTS];
};
+static struct pxa2xx_udc *the_controller;
+
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_ARCH_LUBBOCK
@@ -175,25 +177,6 @@ struct pxa2xx_udc {
/*-------------------------------------------------------------------------*/
-static struct pxa2xx_udc *the_controller;
-
-static inline int pxa_gpio_get(unsigned gpio)
-{
- return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
-}
-
-static inline void pxa_gpio_set(unsigned gpio, int is_on)
-{
- int mask = GPIO_bit(gpio);
-
- if (is_on)
- GPSR(gpio) = mask;
- else
- GPCR(gpio) = mask;
-}
-
-/*-------------------------------------------------------------------------*/
-
/*
* Debugging support vanishes in non-debug builds. DBG_NORMAL should be
* mostly silent during normal use/testing, with no timing side-effects.
Index: pxa/arch/arm/mach-pxa/corgi_ssp.c
===================================================================
--- pxa.orig/arch/arm/mach-pxa/corgi_ssp.c 2006-12-10 01:30:42.000000000 -0800
+++ pxa/arch/arm/mach-pxa/corgi_ssp.c 2006-12-29 16:16:18.000000000 -0800
@@ -16,6 +16,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -52,13 +54,13 @@ unsigned long corgi_ssp_ads7846_putget(u
spin_lock_irqsave(&corgi_ssp_lock, flag);
if (ssp_machinfo->cs_ads7846 >= 0)
- GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
+ gpio_set_value(ssp_machinfo->cs_ads7846, 0);
ssp_write_word(&corgi_ssp_dev,data);
ssp_read_word(&corgi_ssp_dev, &ret);
if (ssp_machinfo->cs_ads7846 >= 0)
- GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
+ gpio_set_value(ssp_machinfo->cs_ads7846, 1);
spin_unlock_irqrestore(&corgi_ssp_lock, flag);
return ret;
@@ -78,7 +80,7 @@ void corgi_ssp_ads7846_lock(void)
void corgi_ssp_ads7846_unlock(void)
{
if (ssp_machinfo->cs_ads7846 >= 0)
- GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
+ gpio_set_value(ssp_machinfo->cs_ads7846, 1);
spin_unlock(&corgi_ssp_lock);
}
@@ -124,7 +126,7 @@ unsigned long corgi_ssp_dac_put(ulong da
/* Read null data back from device to prevent SSP overflow */
ssp_read_word(&corgi_ssp_dev, &tmp);
if (ssp_machinfo->cs_lcdcon >= 0)
- GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
+ gpio_set_value(ssp_machinfo->cs_lcdcon, 1);
ssp_disable(&corgi_ssp_dev);
ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
@@ -181,7 +183,7 @@ int corgi_ssp_max1111_get(ulong data)
ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
ssp_enable(&corgi_ssp_dev);
if (ssp_machinfo->cs_max1111 >= 0)
- GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
+ gpio_set_value(ssp_machinfo->cs_max1111, 1);
spin_unlock_irqrestore(&corgi_ssp_lock, flag);
if (voltage1 & 0xc0 || voltage2 & 0x3f)
@@ -245,11 +247,11 @@ static int corgi_ssp_suspend(struct plat
static int corgi_ssp_resume(struct platform_device *dev)
{
if (ssp_machinfo->cs_lcdcon >= 0)
- GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */
+ gpio_set_value(ssp_machinfo->cs_lcdcon, 1); /* High - Disable LCD Control/Timing Gen */
if (ssp_machinfo->cs_max1111 >= 0)
- GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
+ gpio_set_value(ssp_machinfo->cs_max1111, 1); /* High - Disable MAX1111*/
if (ssp_machinfo->cs_ads7846 >= 0)
- GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
+ gpio_set_value(ssp_machinfo->cs_ads7846, 1); /* High - Disable ADS7846*/
ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
ssp_enable(&corgi_ssp_dev);
Index: pxa/drivers/usb/gadget/pxa2xx_udc.c
===================================================================
--- pxa.orig/drivers/usb/gadget/pxa2xx_udc.c 2006-12-27 13:38:43.000000000 -0800
+++ pxa/drivers/usb/gadget/pxa2xx_udc.c 2006-12-29 16:45:58.000000000 -0800
@@ -47,6 +47,7 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
@@ -156,7 +157,7 @@ static int is_vbus_present(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
- return pxa_gpio_get(mach->gpio_vbus);
+ return gpio_get_value(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@@ -168,7 +169,7 @@ static void pullup_off(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- pxa_gpio_set(mach->gpio_pullup, 0);
+ gpio_set_value(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
@@ -178,7 +179,7 @@ static void pullup_on(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- pxa_gpio_set(mach->gpio_pullup, 1);
+ gpio_set_value(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
@@ -1636,7 +1637,14 @@ int usb_gadget_register_driver(struct us
dev->gadget.dev.driver = &driver->driver;
dev->pullup = 1;
- device_add (&dev->gadget.dev);
+ retval = device_add (&dev->gadget.dev);
+ if (retval < 0) {
+ DMSG("add gadget dev --> error %d\n", retval);
+
+ dev->driver = NULL;
+ dev->gadget.dev.driver = NULL;
+ return retval;
+ }
retval = driver->bind(&dev->gadget);
if (retval) {
DMSG("bind to driver %s --> error %d\n",
@@ -1647,7 +1655,7 @@ int usb_gadget_register_driver(struct us
dev->gadget.dev.driver = NULL;
return retval;
}
- device_create_file(dev->dev, &dev_attr_function);
+ retval = device_create_file(dev->dev, &dev_attr_function);
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
@@ -1756,7 +1764,7 @@ lubbock_vbus_irq(int irq, void *_dev)
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
- int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
+ int vbus = gpio_get_value(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
Index: pxa/arch/arm/mach-pxa/corgi_pm.c
===================================================================
--- pxa.orig/arch/arm/mach-pxa/corgi_pm.c 2006-12-10 01:30:42.000000000 -0800
+++ pxa/arch/arm/mach-pxa/corgi_pm.c 2006-12-29 16:57:32.000000000 -0800
@@ -20,6 +20,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/hardware.h>
+#include <asm/gpio.h>
#include <asm/hardware/scoop.h>
#include <asm/arch/sharpsl.h>
@@ -45,10 +46,7 @@ static void corgi_charger_init(void)
static void corgi_measure_temp(int on)
{
- if (on)
- GPSR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
- else
- GPCR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+ gpio_set_value(CORGI_GPIO_ADC_TEMP_ON, on);
}
static void corgi_charge(int on)
@@ -69,10 +67,7 @@ static void corgi_charge(int on)
static void corgi_discharge(int on)
{
- if (on)
- GPSR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
- else
- GPCR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+ gpio_set_value(CORGI_GPIO_DISCHARGE_ON, on);
}
static void corgi_presuspend(void)
@@ -81,17 +76,17 @@ static void corgi_presuspend(void)
unsigned long wakeup_mask;
/* charging , so CHARGE_ON bit is HIGH during OFF. */
- if (READ_GPIO_BIT(CORGI_GPIO_CHRG_ON))
+ if (gpio_get_value(CORGI_GPIO_CHRG_ON))
PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_ON);
else
PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_ON);
- if (READ_GPIO_BIT(CORGI_GPIO_LED_ORANGE))
+ if (gpio_get_value(CORGI_GPIO_LED_ORANGE))
PGSR0 |= GPIO_bit(CORGI_GPIO_LED_ORANGE);
else
PGSR0 &= ~GPIO_bit(CORGI_GPIO_LED_ORANGE);
- if (READ_GPIO_BIT(CORGI_GPIO_CHRG_UKN))
+ if (gpio_get_value(CORGI_GPIO_CHRG_UKN))
PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_UKN);
else
PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_UKN);
@@ -171,13 +166,13 @@ unsigned long corgipm_read_devdata(int t
{
switch(type) {
case SHARPSL_STATUS_ACIN:
- return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0);
+ return gpio_get_value(CORGI_GPIO_AC_IN) != 0;
case SHARPSL_STATUS_LOCK:
- return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock);
+ return gpio_get_value(sharpsl_pm.machinfo->gpio_batlock);
case SHARPSL_STATUS_CHRGFULL:
- return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull);
+ return gpio_get_value(sharpsl_pm.machinfo->gpio_batfull);
case SHARPSL_STATUS_FATAL:
- return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal);
+ return gpio_get_value(sharpsl_pm.machinfo->gpio_fatal);
case SHARPSL_ACIN_VOLT:
return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT);
case SHARPSL_BATT_TEMP:
Index: pxa/drivers/video/backlight/corgi_bl.c
===================================================================
--- pxa.orig/drivers/video/backlight/corgi_bl.c 2006-12-10 01:31:55.000000000 -0800
+++ pxa/drivers/video/backlight/corgi_bl.c 2006-12-29 16:34:41.000000000 -0800
@@ -121,7 +121,7 @@ static int corgibl_probe(struct platform
machinfo->limit_mask = -1;
corgi_backlight_device = backlight_device_register ("corgi-bl",
- NULL, &corgibl_data);
+ &pdev->dev, NULL, &corgibl_data);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
Index: pxa/arch/arm/mach-pxa/corgi_lcd.c
===================================================================
--- pxa.orig/arch/arm/mach-pxa/corgi_lcd.c 2006-12-10 01:30:42.000000000 -0800
+++ pxa/arch/arm/mach-pxa/corgi_lcd.c 2006-12-29 16:45:42.000000000 -0800
@@ -20,6 +20,8 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/string.h>
+
+#include <asm/gpio.h>
#include <asm/arch/akita.h>
#include <asm/arch/corgi.h>
#include <asm/hardware.h>
@@ -449,8 +451,10 @@ static unsigned long (*get_hsync_time)(s
static void inline sharpsl_wait_sync(int gpio)
{
- while((GPLR(gpio) & GPIO_bit(gpio)) == 0);
- while((GPLR(gpio) & GPIO_bit(gpio)) != 0);
+ while (gpio_get_value(gpio) == 0)
+ continue;
+ while (gpio_get_value(gpio) != 0)
+ continue;
}
#ifdef CONFIG_PXA_SHARP_C7xx
Index: pxa/drivers/video/backlight/locomolcd.c
===================================================================
--- pxa.orig/drivers/video/backlight/locomolcd.c 2006-12-10 01:31:55.000000000 -0800
+++ pxa/drivers/video/backlight/locomolcd.c 2006-12-29 16:37:31.000000000 -0800
@@ -184,7 +184,8 @@ static int locomolcd_probe(struct locomo
local_irq_restore(flags);
- locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data);
+ locomolcd_bl_device = backlight_device_register("locomo-bl",
+ &ldev->dev, NULL, &locomobl_data);
if (IS_ERR (locomolcd_bl_device))
return PTR_ERR (locomolcd_bl_device);
Index: pxa/arch/arm/mach-pxa/spitz_pm.c
===================================================================
--- pxa.orig/arch/arm/mach-pxa/spitz_pm.c 2006-12-10 01:30:42.000000000 -0800
+++ pxa/arch/arm/mach-pxa/spitz_pm.c 2006-12-29 16:50:47.000000000 -0800
@@ -176,11 +176,11 @@ unsigned long spitzpm_read_devdata(int t
case SHARPSL_STATUS_ACIN:
return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0);
case SHARPSL_STATUS_LOCK:
- return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock);
+ return gpio_get_value(sharpsl_pm.machinfo->gpio_batlock);
case SHARPSL_STATUS_CHRGFULL:
- return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull);
+ return gpio_get_value(sharpsl_pm.machinfo->gpio_batfull);
case SHARPSL_STATUS_FATAL:
- return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal);
+ return gpio_get_value(sharpsl_pm.machinfo->gpio_fatal);
case SHARPSL_ACIN_VOLT:
return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT);
case SHARPSL_BATT_TEMP:
Index: pxa/arch/arm/mach-pxa/sharpsl.h
===================================================================
--- pxa.orig/arch/arm/mach-pxa/sharpsl.h 2006-12-10 01:30:42.000000000 -0800
+++ pxa/arch/arm/mach-pxa/sharpsl.h 2006-12-29 16:51:14.000000000 -0800
@@ -44,12 +44,6 @@ void corgi_wait_hsync(void);
void spitz_wait_hsync(void);
-/*
- * SharpSL Battery/PM Driver
- */
-
-#define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x))
-
/* MAX1111 Channel Definitions */
#define MAX1111_BATT_VOLT 4u
#define MAX1111_BATT_TEMP 2u
On Thursday 28 December 2006 4:27 pm, Pavel Machek wrote:
>
> > > > +GPIOs are identified by unsigned integers in the range 0..MAX_INT....
> > >
> > > Perhaps these should not be integers, then?
> >
> > Thing is, the platforms **DO** identify them as integers.
> > ...
>
> Well. when you see (something) = gpio_number + 5 ... you most likely
> have an error.
One could surely apply that argument to hundreds of places throughout
the kernel ... that doesn't make it a good one. One of the downfalls
of many "object oriented programming" efforts was this same desire to
encapsulate things that don't need it; it's lose, not a don't-care.
Think of it as "cookies represented by integers" if you like.
> No, that's a wrong way. I want you to admit that gpio numbers are
> opaque cookies noone should look at, and use (something like)
> gpio_t... so that we can teach sparse to check them.
You're welcome to dream on. :)
The goal here is not to create new complexity, it's to wrap the
current widely used abstraction (gpios are integers, with get/set
primitives and a direction) in a neutral programming interface
that's very easy to map to/from the current arch-specific ones.
So that various drivers can get on with the business of being
generally useful, rather than arch-specific; or at least being
easier to read. See the example PXA patch I recently posted;
it's a code shrink, and *direct* translation from the current
GPIO interface (which uses integers).
> > > > +The get/set calls have no error returns because "invalid GPIO" should have
> > > > +been reported earlier in gpio_set_direction(). However, note that not all
> > > > +platforms can read the value of output pins; those that can't should always
> > > > +return zero. Also, these calls will be ignored for GPIOs that can't safely
> > > > +be accessed without sleeping (see below).
> > >
> > > 'Silently ignored' is ugly. BUG() would be okay there.
> >
> > The reason for "silently ignored" is that we really don't want to be
> > cluttering up the code (source or object) with logic to test for this
> > kind of "can't happen" failure, especially since there's not going to
> > be any way to _resolve_ such failures cleanly.
>
> You may not want to clutter up code for one arch, but for some of them
> maybe it is okay and welcome. Please do not document "silently
> ignored" into API.
Those words were yours; so you can consider that already done.
Should it instead say that's an (obviously unchecked) error?
The "no error returns" was an explicit request from several folk
during earlier API discussions. People actually _using_ GPIOs have
no use for faults on those known-valid get/set calls. Seriously,
exactly how could you ever recover from register access no longer
working correctly? The chip is in the process of exploding, or
being crushed; what could software possibly do to recover?
> > And per Linus' rule about BUG(), "silently ignored" is clearly better
> > than needlessly stopping the whole system.
>
> You are perverting what Linus said. "Do not bother detecting errors"
> is not what he had in mind.. but perhaps it should be WARN() not
> BUG().
You are perverting what _I_ said. (As you've done before; stop that.)
It's very clear that I was talking about a tradeoff ("better than"), and
pointing out how Linus' rule made it clear that your proposal was on the
wrong end of things. (His rule being that BUG should not be used unless
the system really can't continue operating.)
In terms of API specs, emitting any warning is traditionally out-of-scope.
Because "of course" it's legit for debug modes to do all kinds of things,
including emitting warnings; and likewise it's legit for non-debug modes
to do nothing not absolutely required. And programming interface specs
have no business in "quality of implementation" issues like whether any
implementation even _has_ a debug mode, much less what it covers.
> > > > +... It is an unchecked error to use a GPIO
> > > > +number that hasn't been marked as an input using gpio_set_direction(), or
> > >
> > > It should be valid to do irqs on outputs,
> >
> > Good point -- it _might_ be valid to do that, on some platforms.
> > Such things have been used as a software IRQ trigger, which can
> > make bootstrapping some things easier.
> >
> > That's not incompatible with it being an error for portable code to
> > try that, or with refusing to check it so that those platforms don't
> > needlessly cause trouble!
>
> I believe your text suggests it _is_ incompatible. Plus that seems to
> mean that architecture must not check for that error...
Which -- that portable code mustn't try such things? That seems clearly
wrong; that's what the "is an error" phrase means. Or that code should
not need an obscure API for nonportable tricks like that? That seems
wrong too; that's one of the reasons to specify things as "unchecked".
Or that implementations shouldn't be required to guard against that
behavior in layers above? Same comment about "unchecked".
I think you must have missed the class in "how to write API specs" which
discussed how to accomodate nonportable behaviors; it's a given that if
there are more than two implementations of the interface, such things are
going to exist. One of the options is to just declare such things as
clearly out-of-scope for the API, and just wash your hands of what some
implementaiton will be doing (regardless of what you write down). In
this case, that's what happened.
And again, remember that if your implementation (not architecture!) wants
to have a (debug) mode that warns about marginal might-be-trouble cases,
that's always legit.
- Dave
On Thu, 28 Dec 2006, David Brownell wrote:
> Phillip: is this the final version, then? It's missing
> a signed-off-by line, so I can't do anything appropriate.
>
> Nico, your signoff here would be a Good Thing too if it
> meets your technical review. (My only comment, ISTR, was
> that gpio_set_value macro should probably test for whether
> the value is a constant too, not just the gpio pin.)
I don't think so. Expansion of GPIO_bit(x) is pretty simple even if x
is not constant. That probably makes it still less costly than a
function call.
Nicolas
Here's a version that compiles ...
On Friday 29 December 2006 6:15 pm, Nicolas Pitre wrote:
> On Thu, 28 Dec 2006, David Brownell wrote:
>
> > Phillip: is this the final version, then? It's missing
> > a signed-off-by line, so I can't do anything appropriate.
> >
> > Nico, your signoff here would be a Good Thing too if it
> > meets your technical review. (My only comment, ISTR, was
> > that gpio_set_value macro should probably test for whether
> > the value is a constant too, not just the gpio pin.)
>
> I don't think so. Expansion of GPIO_bit(x) is pretty simple even if x
> is not constant. That probably makes it still less costly than a
> function call.
I was more concerned with the "value" ... that expands to a conditional,
which is likely to cost a couple more instructions regardless, which in
space terms competes with a function call.
But I concluded much the same thing when I did that experimental
conversion ... not because I was comparing the space for conditional
vs funcall, but because the existing code already had the conditional.
If more code savings can be had later, so be it ... no rush for now.
- Dave
On Fri, 29 Dec 2006, David Brownell wrote:
> Here's a version that compiles ...
This patch is completely broken.
> Arch-neutral GPIO calls for PXA.
This is not PXA but SA1100 to start with.
> Signed-off-by: David Brownell <[email protected]>
>
> Index: pxa/include/asm-arm/arch-sa1100/gpio.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ pxa/include/asm-arm/arch-sa1100/gpio.h 2006-12-29
> 18:21:00.000000000 -0800
> @@ -0,0 +1,100 @@
[...]
> +static inline int gpio_direction_input(unsigned gpio)
> +{
> + if (gpio > GPIO_MAX)
> + return -EINVAL;
> + GPDR = (GPDR_In << gpio);
This is crap. It will expand to GPDR = 0 effectively making _all_ gpios
as input.
What you want here is:
GPDR &= ~(1 << gpio);
and you most probably need to protect the implied read-modify-write
cycle with a spinlock unless the generic gpio API expects this
protection is the responsibility of the caller.
> +static inline int gpio_direction_output(unsigned gpio)
> +{
> + if (gpio > GPIO_MAX)
> + return -EINVAL;
> + GPDR = (GPDR_Out << gpio);
Same issue, although this would make all gpios as input except for the
specified one.
What you want is:
GPDR |= (1 << gpio);
And again spinlock protection is probably needed.
> +static inline int __gpio_get_value(unsigned gpio)
> +{
> + return GPLR & GPIO_GPIO(gpio);
> +}
> +
> +#define gpio_get_value(gpio) \
> + (__builtin_constant_p(gpio) \
> + ? __gpio_get_value(gpio) \
> + : sa1100_gpio_get_value(gpio))
> +
Please drop the out of line version. It will always be more costly than
the inline version even for non constant gpio values. And I think the
usage of GPIO_GPIO(gpio) is more obfuscating than directly using
(1 << gpio).
> +static inline void __gpio_set_value(unsigned gpio, int value)
> +{
> + if (value)
> + GPSR = GPIO_GPIO(gpio);
> + else
> + GPCR = GPIO_GPIO(gpio);
> +}
> +
> +#define gpio_set_value(gpio,value) \
> + (__builtin_constant_p(gpio) \
> + ? __gpio_set_value(gpio, value) \
> + : sa1100_gpio_set_value(gpio, value))
Same as above.
Nicolas
On Friday 29 December 2006 7:15 pm, Nicolas Pitre wrote:
> On Fri, 29 Dec 2006, David Brownell wrote:
>
> > Here's a version that compiles ...
>
> This patch is completely broken.
It's just what Philipp sent, with the "won't compile" bugs fixed.
Oh, and some #include tweaks. Philipp?
> > Arch-neutral GPIO calls for PXA.
>
> This is not PXA but SA1100 to start with.
I seem to have copied the wrong header comment, sorry; the original
patch had none. It's marginally better than the header claiming it
was a PXA header...
> and you most probably need to protect the implied read-modify-write
> cycle with a spinlock unless the generic gpio API expects this
> protection is the responsibility of the caller.
No such lock is known to the caller. Some of those calls will need
to move to a C file somewhere.
- Dave
On 12/30/06, David Brownell <[email protected]> wrote:
> On Friday 29 December 2006 7:15 pm, Nicolas Pitre wrote:
> > On Fri, 29 Dec 2006, David Brownell wrote:
> >
> > > Here's a version that compiles ...
> >
> > This patch is completely broken.
>
> It's just what Philipp sent, with the "won't compile" bugs fixed.
> Oh, and some #include tweaks. Philipp?
Corrected version attached. I also removed the out of line versions of
gpio_set/get_value.
> > and you most probably need to protect the implied read-modify-write
> > cycle with a spinlock unless the generic gpio API expects this
> > protection is the responsibility of the caller.
>
> No such lock is known to the caller. Some of those calls will need
> to move to a C file somewhere.
Moved into generic.c
regards
Philipp
----------------------
Signed-off-by: Philipp Zabel <[email protected]>
Index: linux-2.6/include/asm-arm/arch-sa1100/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/asm-arm/arch-sa1100/gpio.h 2006-12-30
14:43:49.000000000 +0100
@@ -0,0 +1,72 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/gpio.h
+ *
+ * SA1100 GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_SA1100_GPIO_H
+#define __ASM_ARCH_SA1100_GPIO_H
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+#define gpio_direction_input sa1100_gpio_direction_output
+#define gpio_direction_output sa1100_gpio_direction_output
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ return GPLR & GPIO_GPIO(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR = GPIO_GPIO(gpio);
+ else
+ GPCR = GPIO_GPIO(gpio);
+}
+
+static inline unsigned gpio_to_irq(unsigned gpio)
+{
+ if (gpio < 11)
+ return IRQ_GPIO0 + gpio;
+ else
+ return IRQ_GPIO11 - 11 + gpio;
+}
+
+static inline unsigned irq_to_gpio(unsigned irq)
+{
+ if (irq < IRQ_GPIO11_27)
+ return irq - IRQ_GPIO0;
+ else
+ return irq - IRQ_GPIO11 + 11;
+}
+
+#endif /* __ASM_ARCH_SA1100_GPIO_H */
Index: linux-2.6/arch/arm/mach-sa1100/generic.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-sa1100/generic.c 2006-12-27
21:50:03.000000000 +0100
+++ linux-2.6/arch/arm/mach-sa1100/generic.c 2006-12-30 14:50:42.000000000 +0100
@@ -138,6 +138,36 @@
return v;
}
+int sa1100_gpio_direction_input(unsigned gpio)
+{
+ unsigned long flags;
+
+ if (gpio > GPIO_MAX)
+ return -EINVAL;
+
+ local_irq_save(flags);
+ GPDR &= ~GPIO_GPIO(gpio);
+ local_irq_restore(flags);
+ return 0;
+}
+
+EXPORT_SYMBOL(sa1100_gpio_direction_input);
+
+int sa1100_gpio_direction_output(unsigned gpio)
+{
+ unsigned long flags;
+
+ if (gpio > GPIO_MAX)
+ return -EINVAL;
+
+ local_irq_save(flags);
+ GPDR |= GPIO_GPIO(gpio);
+ local_irq_restore(flags);
+ return 0;
+}
+
+EXPORT_SYMBOL(sa1100_gpio_direction_output);
+
/*
* Default power-off for SA1100
*/
Index: linux-2.6/include/asm-arm/arch-sa1100/hardware.h
===================================================================
--- linux-2.6.orig/include/asm-arm/arch-sa1100/hardware.h 2006-12-27
21:50:05.000000000 +0100
+++ linux-2.6/include/asm-arm/arch-sa1100/hardware.h 2006-12-30
14:43:30.000000000 +0100
@@ -48,6 +48,9 @@
#endif
+extern int sa1100_gpio_direction_input(unsigned gpio);
+extern int sa1100_gpio_direction_output(unsigned gpio);
+
#include "SA-1100.h"
#ifdef CONFIG_SA1101
On Sat, Dec 30, 2006 at 02:59:39PM +0100, pHilipp Zabel wrote:
> --- linux-2.6.orig/arch/arm/mach-sa1100/generic.c 2006-12-27
> 21:50:03.000000000 +0100
> +++ linux-2.6/arch/arm/mach-sa1100/generic.c 2006-12-30
> 14:50:42.000000000 +0100
> @@ -138,6 +138,36 @@
> return v;
> }
>
> +int sa1100_gpio_direction_input(unsigned gpio)
> +{
> + unsigned long flags;
> +
> + if (gpio > GPIO_MAX)
Obvious space/tab confusion. Please use a consistent indentation style.
> + return -EINVAL;
> +
> + local_irq_save(flags);
Ditto.
> + GPDR &= ~GPIO_GPIO(gpio);
> + local_irq_restore(flags);
Ditto.
> + return 0;
> +}
> +
> +EXPORT_SYMBOL(sa1100_gpio_direction_input);
> +
> +int sa1100_gpio_direction_output(unsigned gpio)
> +{
> + unsigned long flags;
Ditto.
> +
> + if (gpio > GPIO_MAX)
> + return -EINVAL;
> +
> + local_irq_save(flags);
Ditto.
> + GPDR |= GPIO_GPIO(gpio);
> + local_irq_restore(flags);
Ditto.
--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:
> Based on earlier discussion, I'm sending a refresh of the generic GPIO
> patch, with several (ARM based) implementations in separate patches:
Hi Dave,
I'm very interested in seeing an abstraction for gpios. Over the last
several months, I've been working on getting Linux running on my phone
- see http://www.handhelds.org for more information. These types of ARM
based PDAs and phones are riddled with GPIOs, and there is frequent
code duplication when two machines have to do similar functionality
with different gpios.
Unfortunately, I fear the implementation you propose is not robust
enough to handle the cases I need to handle. In particular, I think a
"struct gpio" instead of "int gpio" is needed to describe a gpio pin.
Some background - on the phone I use, it has the standard PXA27x
gpios, a gpio extender chip (egpio) which is connected via the memory
bus, and a micro-controller attached via an i2c like bus. Other
phones will commonly have the PXA27x, "egpio", and an "asic3" chip.
With the sale of the PXA line, it seems Samsung and TI based ARM chips
(and their corresponding GPIOs) will be on the rise.
As you know, basic functionality like setting a LED, detecting a
button press, requesting an irq, etc. are common with GPIOs regardless
of which platform, or which gpio chip, is in use.
The concern I have with your current implementation is that I don't
see a way to flexibly add in support for additional gpio pins on a
machine by machine basis. The code does do a good job of abstracting
gpios based on the primary architecture (eg, PXA vs OMAP), but not on
a chip basis (eg, PXA vs ASIC3).
Specifically, once the code pulls in "<asm/gpio.h>" it will get the
PXA gpio code, but this will only allow access to the arch gpios, not
the machine specific gpios. Also, one of the goals of the developers
at handhelds.org is to have one kernel for many different phones --
from a userspace point of view they don't generally differ very much.
As such, this isn't a matter of just having each "machine" override
the gpio.h file at compile time; it really needs to be done at
runtime.
I understand that the existing code works entirely on integers.
However, I fear this is at attribute of the problem, not of the
solution.
> - Core patch, doc + <asm-arm/gpio.h> + <asm-generic/gpio.h>
> - OMAP implementation
> - AT91 implementation
> - PXA implementation
> - SA1100 implementation
> - S3C2410 implementation
Your patch clearly shows that the existing implementations are using
integers. I think there is a simple way to reuse the existing
implementations. For example on pxa one could do something like:
============= include/linux/gpio.h
struct gpio_ops {
int (*gpio_direction_input)(struct *gpio);
...
};
struct gpio {
struct gpio_ops *ops;
};
============= arch/arm/mach-pxa/gpio.c
struct gpio pxa_gpios[120] = {
{.ops = pxa_gpio_ops}, ...
};
int pxa_gpio_direction_input(struct *gpio) {
int pxa_gpio = gpio - pxa_gpios;
pxa_gpio_mode(pxa_gpio | GPIO_IN);
return 0;
}
...
> Other than clarifications, the main change in the doc is defining
> new calls safe for use with GPIOs on things like pcf8574 I2C gpio
> expanders; those new calls can sleep, but are otherwise the same as
> the spinlock-safe versions. The implementations above implement that
> as a wrapper (the asm-generic header) around the spinlock-safe calls.
As above, I'm confused how these expanders would work in practice.
The expanders would be present on a machine by machine basis but the
code seems to be implemented on an arch by arch basis. Perhaps an
example would help me.
Please CC me on replies.
Cheers,
-Kevin
For the list archives: here's the latest version of this.
The signed-off-by discussion is offlist right now, so this
version has none; see what eventually merges.
From: Philipp Zabel <[email protected]>
Arch-neutral GPIO calls for PXA.
Index: pxa/include/asm-arm/arch-pxa/gpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ pxa/include/asm-arm/arch-pxa/gpio.h 2007-01-01 11:23:43.000000000 -0800
@@ -0,0 +1,97 @@
+/*
+ * linux/include/asm-arm/arch-pxa/gpio.h
+ *
+ * PXA GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Philipp Zabel <[email protected]>
+ *
+ * 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
+ *
+ */
+
+#ifndef __ASM_ARCH_PXA_GPIO_H
+#define __ASM_ARCH_PXA_GPIO_H
+
+#include <asm/errno.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+
+static inline int gpio_get_value(unsigned gpio);
+static inline void gpio_set_value(unsigned gpio, int value);
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ return pxa_gpio_mode(gpio | GPIO_IN);
+}
+
+static inline int gpio_direction_output(unsigned gpio)
+{
+ return pxa_gpio_mode(gpio | GPIO_OUT);
+}
+
+static inline int __gpio_get_value(unsigned gpio)
+{
+ return GPLR(gpio) & GPIO_bit(gpio);
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ if (__builtin_constant_p(gpio))
+ return __gpio_get_value(gpio);
+ else
+ pxa_gpio_get_value(gpio);
+}
+
+static inline void __gpio_set_value(unsigned gpio, int value)
+{
+ if (value)
+ GPSR(gpio) = GPIO_bit(gpio);
+ else
+ GPCR(gpio) = GPIO_bit(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ if (__builtin_constant_p(gpio))
+ __gpio_set_value(gpio, value);
+ else
+ pxa_gpio_set_value(gpio, value);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ if (gpio <= PXA_LAST_GPIO)
+ return IRQ_GPIO(gpio);
+ return -EINVAL;
+}
+
+#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
+
+
+#endif
Index: pxa/arch/arm/mach-pxa/generic.c
===================================================================
--- pxa.orig/arch/arm/mach-pxa/generic.c 2006-12-31 17:03:59.000000000 -0800
+++ pxa/arch/arm/mach-pxa/generic.c 2006-12-31 17:08:37.000000000 -0800
@@ -36,6 +36,7 @@
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/gpio.h>
#include <asm/arch/udc.h>
#include <asm/arch/pxafb.h>
#include <asm/arch/mmc.h>
@@ -104,13 +105,16 @@ unsigned long long sched_clock(void)
* Handy function to set GPIO alternate functions
*/
-void pxa_gpio_mode(int gpio_mode)
+int pxa_gpio_mode(int gpio_mode)
{
unsigned long flags;
int gpio = gpio_mode & GPIO_MD_MASK_NR;
int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
int gafr;
+ if (gpio > PXA_LAST_GPIO)
+ return -EINVAL;
+
local_irq_save(flags);
if (gpio_mode & GPIO_DFLT_LOW)
GPCR(gpio) = GPIO_bit(gpio);
@@ -123,11 +127,33 @@ void pxa_gpio_mode(int gpio_mode)
gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
local_irq_restore(flags);
+
+ return 0;
}
EXPORT_SYMBOL(pxa_gpio_mode);
/*
+ * Return GPIO level
+ */
+int pxa_gpio_get_value(unsigned gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+EXPORT_SYMBOL(pxa_gpio_get_value);
+
+/*
+ * Set output GPIO level
+ */
+void pxa_gpio_set_value(unsigned gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+EXPORT_SYMBOL(pxa_gpio_set_value);
+
+/*
* Routine to safely enable or disable a clock in the CKEN
*/
void pxa_set_cken(int clock, int enable)
Index: pxa/include/asm-arm/arch-pxa/hardware.h
===================================================================
--- pxa.orig/include/asm-arm/arch-pxa/hardware.h 2006-12-31 17:03:59.000000000 -0800
+++ pxa/include/asm-arm/arch-pxa/hardware.h 2006-12-31 17:08:37.000000000 -0800
@@ -65,7 +65,17 @@
/*
* Handy routine to set GPIO alternate functions
*/
-extern void pxa_gpio_mode( int gpio_mode );
+extern int pxa_gpio_mode( int gpio_mode );
+
+/*
+ * Return GPIO level, nonzero means high, zero is low
+ */
+extern int pxa_gpio_get_value(unsigned gpio);
+
+/*
+ * Set output GPIO level
+ */
+extern void pxa_gpio_set_value(unsigned gpio, int value);
/*
* Routine to enable or disable CKEN
On Sunday 31 December 2006 11:11 am, Kevin O'Connor wrote:
> > Based on earlier discussion, I'm sending a refresh of the generic GPIO
> > patch, with several (ARM based) implementations in separate patches:
>
> Hi Dave,
>
> I'm very interested in seeing an abstraction for gpios.
Good! I suspect most folk who've had to work on a few different
embedded Linux boards have noticed lots of needlessly-different
GPIO code. Not many folk are actually seeing that as more than
just ugliness though.
> Unfortunately, I fear the implementation you propose is not robust
> enough to handle the cases I need to handle.
The _interface_ allows those additional GPIO controllers though.
Specifically of the type you mentioned ... that's why this version
defined new "cansleep" call variants.
> The concern I have with your current implementation is that I don't
> see a way to flexibly add in support for additional gpio pins on a
> machine by machine basis. The code does do a good job of abstracting
> gpios based on the primary architecture (eg, PXA vs OMAP), but not on
> a chip basis (eg, PXA vs ASIC3).
You used the key word: implementation. The interface allows it,
but such board-specific extensions haven't yet been needed; so
they've not yet been implemented.
See the appended for a patch roughly along the lines of what has
previously been discussed here. No interface change, just updated
implementation code. And the additional implementation logic won't
kick on boards that don't need it.
Note that the current implementations are a win even without yet
being able to handle the board-specific external GPIO controllers.
The API is clearer than chip-specific register access, and since
it's arch-neutral it already solves integration problems (like
having one SPI controller driver work on both AT91 and AVR).
> > Other than clarifications, the main change in the doc is defining
> > new calls safe for use with GPIOs on things like pcf8574 I2C gpio
> > expanders; those new calls can sleep, but are otherwise the same as
> > the spinlock-safe versions. The implementations above implement that
> > as a wrapper (the asm-generic header) around the spinlock-safe calls.
>
> As above, I'm confused how these expanders would work in practice.
One approach: updating implementations along the lines the patch below.
Other implementations could work too.
Note that I see that kind of update as happening after the first round
of patches go upstream: accept the interface first, then update boards
to support it ... including later the cansleep calls, on some boards.
I like the idea of first replacing the "old" GPIO accesses with ones
using the new APIs ... and only then starting to convert old I2C (etc)
accesses.
> The expanders would be present on a machine by machine basis but the
> code seems to be implemented on an arch by arch basis. Perhaps an
> example would help me.
An example showing one way to implement that interface ... appended.
The expanders would be board-specific, not arch/.../mach-* specific.
(I try to avoid using the word "machine" there; it's too ambiguous.)
The code below just show how boards could plug in; it doesn't actually
convert any boards to use that infrastructure. It should be obvious
how to do that, if you've got a board needing it which works with the
kernel.org GIT tree...
- Dave
================= CUT HERE
Preliminary version of support for board-specific declaring GPIO controllers,
primarily for use with things like I2C access to GPIOs.
* GPIOs numbered 0..ARCH_GPIO_MAX always use internal arch/SOC specific
controller access, and are spinlock-safe.
* All other GPIO numbers are allocated semi-dynamically, as part of
declaring a GPIO controller, and are assumed spinlock-unsafe.
* Such external GPIO controllers provide a simple ops vector for
setting direction, and accessing GPIO values.
Board-specific init code can declare the controllers, then hand out the
GPIOs to code that needs them.
Index: pxa/include/asm-generic/gpio.h
===================================================================
--- pxa.orig/include/asm-generic/gpio.h 2007-01-01 11:20:14.000000000 -0800
+++ pxa/include/asm-generic/gpio.h 2007-01-01 11:34:42.000000000 -0800
@@ -1,7 +1,51 @@
#ifndef _ASM_GENERIC_GPIO_H
#define _ASM_GENERIC_GPIO_H
-/* platforms that don't directly support access to GPIOs through I2C, SPI,
+#ifdef CONFIG_GPIOLIB
+
+/* Boards with GPIOs accessed through I2C etc can access them through some
+ * gpio expander library code:
+ *
+ * - Define ARCH_GPIO_MAX. All GPIO ids accessed through such expanders
+ * will be above this number. Most other GPIOs are SOC-integrated, and
+ * could be accessed by inlined direct register reads/writes.
+ *
+ * - Board-specific setup code declares each controller and how many GPIOs
+ * it handles. The return value is the first GPIO associated with that
+ * controller; other GPIOs immediately follow. These GPIO numbers are
+ * then handed out to the drivers which need them.
+ *
+ * - Have the gpio management code (request, free, set direction) delegate
+ * to gpiolib for GPIOs above ARCH_MAX; and fail gpio_to_irq() for them.
+ */
+struct gpio_ops {
+ int (*direction_input)(void *, unsigned offset);
+ int (*direction_output)(void *, unsigned offset);
+ int (*get_value)(void *, unsigned offset);
+ int (*set_value)(void *, unsigned offset, int value);
+};
+
+extern int __init gpiolib_define_controller(struct gpio_ops *, void *, int n);
+
+extern int gpiolib_request(unsigned gpio, const char *name);
+extern void gpiolib_free(unsigned gpio);
+extern int gpiolib_direction_input(unsigned gpio);
+extern int gpiolib_direction_output(unsigned gpio);
+
+
+/* for now, assume only arch/soc gpios are spinlock-safe */
+static inline int gpio_cansleep(unsigned gpio)
+{
+ return gpio <= ARCH_GPIO_MAX;
+}
+
+/* these standard gpio calls handle both kinds of GPIO */
+extern int gpio_get_value_cansleep(unsigned gpio);
+extern void gpio_set_value_cansleep(unsigned gpio, int value);
+
+#else
+
+/* boards that don't directly support access to GPIOs through I2C, SPI,
* or other blocking infrastructure can use these wrappers.
*/
@@ -22,4 +66,29 @@ static inline void gpio_set_value_cansle
gpio_set_value(gpio, value);
}
+/* having these gpiolib_*() inlines makes it easy to just kick in
+ * the library code for boards that need it
+ */
+
+static inline int gpiolib_request(unsigned gpio, const char *name)
+{
+ return -EINVAL;
+}
+
+static inline void gpiolib_free(unsigned gpio)
+{
+}
+
+static inline int gpiolib_direction_input(unsigned gpio)
+{
+ return -EINVAL;
+}
+
+static inline int gpiolib_direction_output(unsigned gpio)
+{
+ return -EINVAL;
+}
+
+#endif
+
#endif /* _ASM_GENERIC_GPIO_H */
Index: pxa/lib/Kconfig
===================================================================
--- pxa.orig/lib/Kconfig 2007-01-01 11:20:14.000000000 -0800
+++ pxa/lib/Kconfig 2007-01-01 11:34:42.000000000 -0800
@@ -106,4 +106,10 @@ config IOMAP_COPY
depends on !UML
default y
+#
+# gpiolib support is selected on boards that need it
+#
+config GPIOLIB
+ boolean
+
endmenu
Index: pxa/lib/Makefile
===================================================================
--- pxa.orig/lib/Makefile 2007-01-01 11:20:14.000000000 -0800
+++ pxa/lib/Makefile 2007-01-01 11:34:42.000000000 -0800
@@ -57,6 +57,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+obj-$(CONFIG_GPIOLIB) += gpiolib.o
lib-$(CONFIG_GENERIC_BUG) += bug.o
Index: pxa/lib/gpiolib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ pxa/lib/gpiolib.c 2007-01-01 11:34:42.000000000 -0800
@@ -0,0 +1,192 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+#include <asm/gpio.h>
+
+
+/* This is a simple library to support GPIO controllers not integrated into
+ * system-on-chip level arch support. These are reasonably common on embedded
+ * boards, where their hotpluggability is a non-issue. They are often accessed
+ * through busses like I2C or SPI; getting or setting values for such GPIOs
+ * normally sleeps. (Not always; ucb1x00 GPIOs are a counterexample.)
+ */
+
+struct gpio {
+ struct gpio_ops *ops;
+ void *controller;
+ int base;
+ unsigned n;
+ unsigned long requested[1];
+};
+
+static DEFINE_MUTEX(gpio_lock);
+static struct idr gpio_idr;
+
+static struct gpio *gpionum2gpio(unsigned gpionum)
+{
+ struct gpio *g;
+
+ mutex_lock(&gpio_lock);
+ g = idr_find(&gpio_idr, gpionum);
+ mutex_unlock(&gpio_lock);
+ return g;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* some controllers (e.g. simple FPGA logic) have fixed directions */
+
+int gpiolib_direction_input(unsigned gpionum)
+{
+ struct gpio *g = gpionum2gpio(gpionum);
+
+ if (!g || !g->ops->direction_input)
+ return -EINVAL;
+ return g->ops->direction_input(g->controller, gpionum - g->base);
+}
+EXPORT_SYMBOL_GPL(gpiolib_direction_input);
+
+int gpiolib_direction_output(unsigned gpionum)
+{
+ struct gpio *g = gpionum2gpio(gpionum);
+
+ if (!g || !g->ops->direction_output)
+ return -EINVAL;
+ return g->ops->direction_output(g->controller, gpionum - g->base);
+}
+EXPORT_SYMBOL_GPL(gpiolib_direction_output);
+
+
+/* Might as well have real implementations of request/free. Debug versions
+ * might remember name and direction, and dump state in debugfs...
+ */
+
+int gpiolib_request(unsigned gpionum, const char *name)
+{
+ struct gpio *g = gpionum2gpio(gpionum);
+ unsigned offset;
+ int value;
+
+ if (!g)
+ return -EINVAL;
+ offset = gpionum - g->base;
+
+ mutex_lock(&gpio_lock);
+ value = test_and_set_bit(offset, g->requested);
+ mutex_unlock(&gpio_lock);
+ return value ? -EBUSY : 0;
+}
+EXPORT_SYMBOL_GPL(gpiolib_request);
+
+void gpiolib_free(unsigned gpionum)
+{
+ struct gpio *g = gpionum2gpio(gpionum);
+ unsigned offset;
+
+ if (!g)
+ return;
+ offset = gpionum - g->base;
+
+ mutex_lock(&gpio_lock);
+ clear_bit(offset, g->requested);
+ mutex_unlock(&gpio_lock);
+}
+EXPORT_SYMBOL_GPL(gpiolib_free);
+
+/*-------------------------------------------------------------------------*/
+
+int gpio_get_value_cansleep(unsigned gpionum)
+{
+ struct gpio *g;
+
+ might_sleep();
+ if (!gpio_cansleep(gpionum))
+ return gpio_get_value(gpionum);
+ g = gpionum2gpio(gpionum);
+ if (!g || !g->ops->get_value)
+ return 0;
+ return g->ops->get_value(g->controller, gpionum - g->base);
+}
+EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
+
+void gpio_set_value_cansleep(unsigned gpionum, int value)
+{
+ struct gpio *g;
+
+ might_sleep();
+ if (!gpio_cansleep(gpionum)) {
+ gpio_set_value(gpionum, value);
+ return;
+ }
+ g = gpionum2gpio(gpionum);
+ if (!g || !g->ops->set_value)
+ return;
+ g->ops->set_value(g->controller, gpionum - g->base, value);
+}
+EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+
+/*-------------------------------------------------------------------------*/
+
+/* board-specific arch_initcall() code usually defines external GPIO
+ * controllers available, along with the other board-specific devices.
+ */
+
+int __init
+gpiolib_define_controller(struct gpio_ops *ops, void *controller, int n)
+{
+ struct gpio *g;
+ int value;
+ int gpionum;
+
+ if (n <= 0 || n > BITS_PER_LONG)
+ return -EINVAL;
+
+ idr_pre_get(&gpio_idr, GFP_KERNEL);
+
+ g = kzalloc(sizeof *g, GFP_KERNEL);
+ if (!g)
+ return -ENOMEM;
+
+ g->ops = ops;
+ g->controller = controller;
+ g->n = n;
+
+ mutex_lock(&gpio_lock);
+
+ value = idr_get_new_above(&gpio_idr, g, ARCH_GPIO_MAX + 1, &g->base);
+ if (value < 0)
+ goto fail0;
+ gpionum = g->base;
+ while (n--) {
+ int gpio;
+
+ gpionum++;
+ value = idr_get_new_above(&gpio_idr, g, gpionum, &gpio);
+ if (value < 0 || gpio != gpionum)
+ goto fail;
+ }
+
+ mutex_unlock(&gpio_lock);
+ return g->base;
+
+fail:
+ n = g->n;
+ while (n--)
+ idr_replace(&gpio_idr, NULL, g->base + n);
+fail0:
+ mutex_unlock(&gpio_lock);
+ kfree(g);
+ return value;
+}
+
+static int __init gpio_cansleep_init(void)
+{
+ idr_init(&gpio_idr);
+ return 0;
+}
+postcore_initcall(gpio_cansleep_init);
Index: pxa/include/asm-arm/arch-pxa/gpio.h
===================================================================
--- pxa.orig/include/asm-arm/arch-pxa/gpio.h 2007-01-01 11:34:30.000000000 -0800
+++ pxa/include/asm-arm/arch-pxa/gpio.h 2007-01-01 11:35:13.000000000 -0800
@@ -30,6 +30,8 @@
#include <asm/arch/pxa-regs.h>
+#define ARCH_GPIO_MAX PXA_LAST_GPIO
+
static inline int gpio_get_value(unsigned gpio);
static inline void gpio_set_value(unsigned gpio, int value);
@@ -47,11 +49,15 @@ static inline void gpio_free(unsigned gp
static inline int gpio_direction_input(unsigned gpio)
{
+ if (gpio_cansleep(gpio))
+ return gpiolib_direction_input(gpio);
return pxa_gpio_mode(gpio | GPIO_IN);
}
static inline int gpio_direction_output(unsigned gpio)
{
+ if (gpio_cansleep(gpio))
+ return gpiolib_direction_output(gpio);
return pxa_gpio_mode(gpio | GPIO_OUT);
}
Hi!
> > Well. when you see (something) = gpio_number + 5 ... you most likely
> > have an error.
>
> One could surely apply that argument to hundreds of places throughout
> the kernel ... that doesn't make it a good one. One of the downfalls
> of many "object oriented programming" efforts was this same desire to
> encapsulate things that don't need it; it's lose, not a don't-care.
>
> Think of it as "cookies represented by integers" if you like.
typedef int gpio_t would hurt, and would serve as a useful
documentation hint. Furthermore, you could switch it to enum on
platform where it makes sense.
> > No, that's a wrong way. I want you to admit that gpio numbers are
> > opaque cookies noone should look at, and use (something like)
> > gpio_t... so that we can teach sparse to check them.
>
> You're welcome to dream on. :)
>
> The goal here is not to create new complexity, it's to wrap the
...it adds exactly one line.
> > > > > +The get/set calls have no error returns because "invalid GPIO" should have
> > > > > +been reported earlier in gpio_set_direction(). However, note that not all
> > > > > +platforms can read the value of output pins; those that can't should always
> > > > > +return zero. Also, these calls will be ignored for GPIOs that can't safely
> > > > > +be accessed without sleeping (see below).
> > > >
> > > > 'Silently ignored' is ugly. BUG() would be okay there.
> > >
> > > The reason for "silently ignored" is that we really don't want to be
> > > cluttering up the code (source or object) with logic to test for this
> > > kind of "can't happen" failure, especially since there's not going to
> > > be any way to _resolve_ such failures cleanly.
> >
> > You may not want to clutter up code for one arch, but for some of them
> > maybe it is okay and welcome. Please do not document "silently
> > ignored" into API.
>
> Those words were yours; so you can consider that already done.
> Should it instead say that's an (obviously unchecked) error?
Saying it is an error would be okay by me. (Or "Behaviour of these calls for
GPIOs that can't be safely accessed without sleeping is undefined.").
> You are perverting what _I_ said. (As you've done before; stop
>that.)
Sorry.
> In terms of API specs, emitting any warning is traditionally
> out-of-scope.
Ok, I mis-read your specs as trying to push warnings into the scope.
> > > > > +... It is an unchecked error to use a GPIO
> > > > > +number that hasn't been marked as an input using gpio_set_direction(), or
> > > >
> > > > It should be valid to do irqs on outputs,
> > >
> > > Good point -- it _might_ be valid to do that, on some platforms.
> > > Such things have been used as a software IRQ trigger, which can
> > > make bootstrapping some things easier.
> > >
> > > That's not incompatible with it being an error for portable code to
> > > try that, or with refusing to check it so that those platforms don't
> > > needlessly cause trouble!
> >
> > I believe your text suggests it _is_ incompatible. Plus that seems to
> > mean that architecture must not check for that error...
>
> Which -- that portable code mustn't try such things? That seems clearly
> wrong; that's what the "is an error" phrase means. Or that code
Ok, "debug behaviour is out of scope, again".
What about "Behavour of reading a GPIO that hasn't been marked as an
input using gpio_set_direction() is implementation-defined"?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Monday 01 January 2007 12:55 pm, Pavel Machek wrote:
> > Think of it as "cookies represented by integers" if you like.
>
> typedef int gpio_t would hurt, and would serve as a useful
> documentation hint.
Yes, I agree that such needless obfuscation hurts. ;)
Plus, such a typedef would disagree with Documentation/CodingStyle
which says "... the rule should basically be to NEVER EVER use a
typedef" (with some exceptions not matched here).
> > Should it instead say that's an (obviously unchecked) error?
>
> Saying it is an error would be okay by me. (Or "Behaviour of these calls for
> GPIOs that can't be safely accessed without sleeping is undefined.").
See the appended doc patch ... better?
- Dave
================= CUT HERE
Index: at91/Documentation/gpio.txt
===================================================================
--- at91.orig/Documentation/gpio.txt 2006-12-29 00:00:28.000000000 -0800
+++ at91/Documentation/gpio.txt 2006-12-29 15:47:18.000000000 -0800
@@ -78,7 +78,8 @@ Identifying GPIOs
-----------------
GPIOs are identified by unsigned integers in the range 0..MAX_INT. That
reserves "negative" numbers for other purposes like marking signals as
-"not available on this board", or indicating faults.
+"not available on this board", or indicating faults. Code that doesn't
+touch the underlying hardware treats these integers as opaque cookies.
Platforms define how they use those integers, and usually #define symbols
for the GPIO lines so that board-specific setup code directly corresponds
@@ -139,8 +140,8 @@ issues including wire-OR and output late
The get/set calls have no error returns because "invalid GPIO" should have
been reported earlier in gpio_set_direction(). However, note that not all
platforms can read the value of output pins; those that can't should always
-return zero. Also, these calls will be ignored for GPIOs that can't safely
-be accessed wihtout sleeping (see below).
+return zero. Also, using these calls for GPIOs that can't safely be accessed
+without sleeping (see below) is an error.
Platform-specific implementations are encouraged to optimise the two
calls to access the GPIO value in cases where the GPIO number (and for
@@ -239,7 +240,8 @@ options are part of the IRQ interface, e
system wakeup capabilities.
Non-error values returned from irq_to_gpio() would most commonly be used
-with gpio_get_value().
+with gpio_get_value(), for example to initialize or update driver state
+when the IRQ is edge-triggered.
@@ -262,7 +264,8 @@ like the aforementioned options for inpu
Hardware may support reading or writing GPIOs in gangs, but that's usually
configuration dependednt: for GPIOs sharing the same bank. (GPIOs are
commonly grouped in banks of 16 or 32, with a given SOC having several such
-banks.) Code relying on such mechanisms will necessarily be nonportable.
+banks.) Some systems can trigger IRQs from output GPIOs. Code relying on
+such mechanisms will necessarily be nonportable.
Dynamic definition of GPIOs is not currently supported; for example, as
a side effect of configuring an add-on board with some GPIO expanders.
Hi Dave,
On Mon, Jan 01, 2007 at 12:06:19PM -0800, David Brownell wrote:
> > The concern I have with your current implementation is that I don't
> > see a way to flexibly add in support for additional gpio pins on a
> > machine by machine basis. The code does do a good job of abstracting
> > gpios based on the primary architecture (eg, PXA vs OMAP), but not on
> > a chip basis (eg, PXA vs ASIC3).
>
> You used the key word: implementation. The interface allows it,
> but such board-specific extensions haven't yet been needed; so
> they've not yet been implemented.
>
> See the appended for a patch roughly along the lines of what has
> previously been discussed here. No interface change, just updated
> implementation code. And the additional implementation logic won't
> kick on boards that don't need it.
Thanks for enlightening me on previous discussions. The interface in
the "gpiolib" patch is along the lines of what I'm looking for.
However, I still feel this approach is backwards. Going from a
'struct gpio' to an 'int gpio' is easy. Attempting to go from an 'int
gpio' to a 'struct gpio' is hard, as the code you provide
demonstrates.
Can you help explain what the gain to using an integer over a 'struct
gpio' is? I can't help but feel that fundamentally gpios are not
integers and that it is a mistake to code an API around that concept.
> Note that the current implementations are a win even without yet
> being able to handle the board-specific external GPIO controllers.
> The API is clearer than chip-specific register access, and since
> it's arch-neutral it already solves integration problems (like
> having one SPI controller driver work on both AT91 and AVR).
I agree that the code you provide is a big step up from the existing
code. We also both seem to agree that more than just an arch
abstraction is necessary (the cansleep stuff seems to be an
acknowledgment of this).
However, I don't understand the downside to making the API sane from
the start and avoiding the artificial integer namespace problems.
> Note that I see that kind of update as happening after the first round
> of patches go upstream: accept the interface first, then update boards
> to support it ... including later the cansleep calls, on some boards.
Once many of the problems are fixed, I fear fixing the remaining will
be a harder sell. Due to the difficulty of implementing kernel wide
APIs, I suspect some maintainers will just stick to cramming features
in the arch directory (as your patch encourages) which can lead to
duplicated code and fragmented implementations.
Thanks for working on this.
-Kevin
Hi!
> > > Should it instead say that's an (obviously unchecked) error?
> >
> > Saying it is an error would be okay by me. (Or "Behaviour of these calls for
> > GPIOs that can't be safely accessed without sleeping is undefined.").
>
> See the appended doc patch ... better?
Yes, thanks.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html