How to add GPIO outputs to the PXA2xx MFP configuration?
Paul Parsons
lost.distance at yahoo.com
Fri Mar 30 17:40:47 EDT 2012
--- On Fri, 30/3/12, Paul Parsons <lost.distance at yahoo.com> wrote:
> --- On Fri, 30/3/12, Igor Grinberg
> <grinberg at compulab.co.il>
> wrote:
> > On 03/30/12 18:52, Paul Parsons
> > wrote:
> > > --- On Fri, 30/3/12, Igor Grinberg <grinberg at compulab.co.il>
> > wrote:
> > >> On 03/30/12 18:06, Paul Parsons wrote:
> > >>> --- On Fri, 30/3/12, Igor Grinberg <grinberg at compulab.co.il>
> > >> wrote:
> > >>>> On 03/28/12 20:12, Paul Parsons
> > >>>> wrote:
> > >>>>> On PXA2xx platforms, the MFP API
> > (described in
> > >>>> Documentation/arm/pxa/mfp.txt)
> > >>>>> provides values for the
> following:
> > >>>>>
> > >>>>> 1. GPIO inputs (e.g.
> GPIO105_GPIO).
> > >>>>> 2. Alternate function inputs
> (e.g.
> > >> GPIO105_CIF_DD_1).
> > >>>>> 3. Alternate function outputs
> (e.g.
> > >>>> GPIO105_KP_MKOUT_2).
> > >>>>>
> > >>>>> It does not provide values for
> GPIO
> > outputs
> > >> (i.e. AF0
> > >>>> outputs).
> > >>>>>
> > >>>>> One cannot use the macro used by
> the
> > MFP API
> > >> internally
> > >>>> - MFP_CFG_OUT() - to
> > >>>>> define new GPIO output values,
> since
> > that macro
> > >> is
> > >>>> forbidden in platform code.
> > >>>>>
> > >>>>> Without the ability to add GPIO
> outputs
> > to the
> > >> MFP
> > >>>> configuration, it is not
> > >>>>> possible to drive GPIO outputs
> high
> > during
> > >> sleep mode.
> > >>>>>
> > >>>>> This would be useful, for example,
> on
> > the
> > >> hx4700
> > >>>> platform, where driving the
> > >>>>> infrared powerdown GPIO 105 high
> during
> > sleep
> > >> mode
> > >>>> would save some mA.
> > >>>>>
> > >>>>> So my question is: what method
> should
> > one use
> > >> to add
> > >>>> GPIO outputs to the MFP
> > >>>>> configuration?
> > >>>>>
> > >>>>> One possible method, namely
> manually
> > defining
> > >> values in
> > >>>> the platform code:
> > >>>>>
> > >>>>> MFP_PIN_GPIO105 |
> > >> MFP_AF0 |
> > >>>> MFP_DIR_OUT | MFP_LPM_DRIVE_HIGH,
> > >>>>
> > >>>> Have you tried:
> > >>>> GPIO105_GPIO | MFP_LPM_DRIVE_HIGH,
> > >>>> ?
> > >>>>
> > >>>> This way it works on other boards.
> > >>>
> > >>> Hello Igor,
> > >>>
> > >>> GPIO105_GPIO expands to a GPIO input -
> > >> MFP_CFG_IN(GPIO105, AF0) -
> > >>> not an output.
> > >>
> > >> Yeah, I know... but read in mfp-pxa2xx.h,
> lines
> > 6-20:
> > >> /*
> > >> * the following MFP_xxx bit definitions in
> > mfp.h are
> > >> re-used for pxa2xx:
> > >> *
> > >> * MFP_PIN(x)
> > >> * MFP_AFx
> > >> * MFP_LPM_DRIVE_{LOW, HIGH}
> > >> * MFP_LPM_EDGE_x
> > >> *
> > >> * other MFP_x bit definitions will be
> > ignored
> > >> *
> > >> * and adds the below two bits specifically
> > for pxa2xx:
> > >> *
> > >> * bit 23 -
> > Input/Output (PXA2xx
> > >> specific)
> > >> * bit 24 - Wakeup
> > Enable(PXA2xx
> > >> specific)
> > >> */
> > >>
> > >> This means, that there is no difference
> between:
> > MFP_CFG_IN
> > >> and MFP_CFG_OUT for PXA2xx.
> > >
> > > The mfp-pxa2xx.c code says otherwise.
> >
> > That's just great... outdated documentation...
> >
> > > It uses the MFP direction bit
> > > to set the GPDR registers on entering sleep mode:
> > >
> > > 353 static int
> > pxa2xx_mfp_suspend(void)
> > > 354 {
> > > 355
> > int i;
> > > ...
> > > 368
> > for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++)
> {
> > > 369
> > > ...
> > > 375
> > GPDR(i * 32) = gpdr_lpm[i];
> > > 376
> > }
> > > 377
> > return 0;
> > > 378 }
> > >
> > > gpdr_lpm[] is initialized at startup to the
> current
> > GPDR values, and
> > > thereafter is updated by the value of the
> MFP_DIR_OUT
> > bit in calls to
> > > __mfp_config_gpio().
> >
> > static int __mfp_config_gpio(unsigned gpio, unsigned
> long
> > c)
> > {
> > unsigned long gafr, mask =
> > GPIO_bit(gpio);
> > int bank = gpio_to_bank(gpio);
> > int uorl = !!(gpio & 0x10); /*
> > GAFRx_U or GAFRx_L ? */
> > int shft = (gpio & 0xf) << 1;
> > int fn = MFP_AF(c);
> > int is_out = (c & MFP_DIR_OUT) ? 1 :
> > 0;
> >
> > [...]
> >
> > /* alternate function and direction at
> > low power mode */
> > switch (c & MFP_LPM_STATE_MASK) {
> > case MFP_LPM_DRIVE_HIGH:
> > PGSR(bank) |= mask;
> > is_out = 1;
> > break;
> > case MFP_LPM_DRIVE_LOW:
> > PGSR(bank) &=
> > ~mask;
> > is_out = 1;
> > break;
> >
> > And in the lines above, it gets overridden by
> > MFP_LPM_DRIVE_*,
> > or am I missing something?
>
> No, that looks to be the case: the LPM states DRIVE_HIGH and
> DRIVE_LOW
> override the sleep mode direction. I completely missed
> that.
>
> > [...]
> >
> > if (is_out ^
> > gpio_desc[gpio].dir_inverted)
> > gpdr_lpm[bank] |=
> > mask;
> > else
> > gpdr_lpm[bank] &=
> > ~mask;
> >
> >
> > So, I think,
> > GPIO105_GPIO | MFP_LPM_DRIVE_HIGH,
> > as I've proposed in my first email, should still work
> for
> > you.
>
> Yes it should. Thanks.
However MFP_LPM_KEEP_OUTPUT does not do likewise, so for example:
GPIO72_GPIO | MFP_LPM_KEEP_OUTPUT,
will set GPIO72 as an input in sleep mode. hmm...
More information about the linux-arm-kernel
mailing list