diff mbox

[3/3] GPIO: gpio-dwapb: Suspend & Resume PM enabling

Message ID 1409161588-19417-4-git-send-email-alvin.chen@intel.com
State Superseded, archived
Headers show

Commit Message

Chen, Alvin Aug. 27, 2014, 5:46 p.m. UTC
This patch enables suspend and resume mode for the power management, and
it is based on Josef Ahmad's previous work.

Reviewed-by: Hock Leong Kweh <hock.leong.kweh@intel.com>
Reviewed-by: Shevchenko, Andriy <andriy.shevchenko@intel.com>
Signed-off-by: Weike Chen <alvin.chen@intel.com>
---
 drivers/gpio/gpio-dwapb.c |   67 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

Comments

atull Aug. 27, 2014, 4:15 p.m. UTC | #1
On Wed, 27 Aug 2014, Weike Chen wrote:

> This patch enables suspend and resume mode for the power management, and
> it is based on Josef Ahmad's previous work.
> 
> Reviewed-by: Hock Leong Kweh <hock.leong.kweh@intel.com>
> Reviewed-by: Shevchenko, Andriy <andriy.shevchenko@intel.com>
> Signed-off-by: Weike Chen <alvin.chen@intel.com>
> ---
>  drivers/gpio/gpio-dwapb.c |   67 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 67 insertions(+)
> 

Hi Weike,

I tried out these patches on the current master branch (v3.17-rc2-9-g68e3702) with a socfpga cyclone5 board.

If I apply all 3 patches, the kernel doesn't boot.

If I rebuild with only the first patch, I get only one gpio block showing up (should
have 3 for this board) and these messages:

------------[ cut here ]------------
WARNING: CPU: 0 PID: 1 at /home/atull/repos/linux-socfpga/fs/sysfs/dir.c:31 sysfs_warn_dup+0x58/0x74()
sysfs: cannot create duplicate filename '/class/gpio/gpiochip0'
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.17.0-rc2-00012-g7ad6a41 #1
[<c0014ab4>] (unwind_backtrace) from [<c0011684>] (show_stack+0x10/0x14)
[<c0011684>] (show_stack) from [<c03d3d80>] (dump_stack+0x74/0x90)
[<c03d3d80>] (dump_stack) from [<c0020c88>] (warn_slowpath_common+0x68/0x8c)
[<c0020c88>] (warn_slowpath_common) from [<c0020d40>] (warn_slowpath_fmt+0x30/0x40)
[<c0020d40>] (warn_slowpath_fmt) from [<c0144e5c>] (sysfs_warn_dup+0x58/0x74)
[<c0144e5c>] (sysfs_warn_dup) from [<c0145180>] (sysfs_do_create_link_sd+0xbc/0xc4)
[<c0145180>] (sysfs_do_create_link_sd) from [<c02357f4>] (device_add+0x304/0x4ec)
[<c02357f4>] (device_add) from [<c0235a78>] (device_create_groups_vargs+0x9c/0xcc)
[<c0235a78>] (device_create_groups_vargs) from [<c0235af4>] (device_create_vargs+0x20/0x28)
[<c0235af4>] (device_create_vargs) from [<c0235b1c>] (device_create+0x20/0x28)
[<c0235b1c>] (device_create) from [<c020be4c>] (gpiochip_export+0x4c/0x98)
[<c020be4c>] (gpiochip_export) from [<c020a408>] (gpiochip_add+0x114/0x29c)
[<c020a408>] (gpiochip_add) from [<c020c818>] (dwapb_gpio_probe+0x16c/0x634)
[<c020c818>] (dwapb_gpio_probe) from [<c0239198>] (platform_drv_probe+0x2c/0x5c)
[<c0239198>] (platform_drv_probe) from [<c0237bd4>] (driver_probe_device+0x78/0x208)
[<c0237bd4>] (driver_probe_device) from [<c0237df0>] (__driver_attach+0x8c/0x90)
[<c0237df0>] (__driver_attach) from [<c02364b8>] (bus_for_each_dev+0x54/0x88)
[<c02364b8>] (bus_for_each_dev) from [<c023748c>] (bus_add_driver+0xd8/0x1d4)
[<c023748c>] (bus_add_driver) from [<c0238564>] (driver_register+0x78/0xf4)
[<c0238564>] (driver_register) from [<c0008884>] (do_one_initcall+0x80/0x1b8)
[<c0008884>] (do_one_initcall) from [<c052fcd4>] (kernel_init_freeable+0x170/0x240)
[<c052fcd4>] (kernel_init_freeable) from [<c03d0238>] (kernel_init+0x8/0xec)
[<c03d0238>] (kernel_init) from [<c000e578>] (ret_from_fork+0x14/0x3c)
---[ end trace 209e273f37ff62dd ]---
gpiochip_add: GPIOs 0..28 (ff709000.gpio) failed to register
gpio-dwapb ff709000.gpio: failed to register gpiochip for /soc/gpio@ff709000/gpio-controller@0
gpio-dwapb: probe of ff709000.gpio failed with error -17
------------[ cut here ]------------
WARNING: CPU: 0 PID: 1 at /home/atull/repos/linux-socfpga/fs/sysfs/dir.c:31 sysfs_warn_dup+0x58/0x74()
sysfs: cannot create duplicate filename '/class/gpio/gpiochip0'
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W      3.17.0-rc2-00012-g7ad6a41 #1
[<c0014ab4>] (unwind_backtrace) from [<c0011684>] (show_stack+0x10/0x14)
[<c0011684>] (show_stack) from [<c03d3d80>] (dump_stack+0x74/0x90)
[<c03d3d80>] (dump_stack) from [<c0020c88>] (warn_slowpath_common+0x68/0x8c)
[<c0020c88>] (warn_slowpath_common) from [<c0020d40>] (warn_slowpath_fmt+0x30/0x40)
[<c0020d40>] (warn_slowpath_fmt) from [<c0144e5c>] (sysfs_warn_dup+0x58/0x74)
[<c0144e5c>] (sysfs_warn_dup) from [<c0145180>] (sysfs_do_create_link_sd+0xbc/0xc4)
[<c0145180>] (sysfs_do_create_link_sd) from [<c02357f4>] (device_add+0x304/0x4ec)
[<c02357f4>] (device_add) from [<c0235a78>] (device_create_groups_vargs+0x9c/0xcc)
[<c0235a78>] (device_create_groups_vargs) from [<c0235af4>] (device_create_vargs+0x20/0x28)
[<c0235af4>] (device_create_vargs) from [<c0235b1c>] (device_create+0x20/0x28)
[<c0235b1c>] (device_create) from [<c020be4c>] (gpiochip_export+0x4c/0x98)
[<c020be4c>] (gpiochip_export) from [<c020a408>] (gpiochip_add+0x114/0x29c)
[<c020a408>] (gpiochip_add) from [<c020c818>] (dwapb_gpio_probe+0x16c/0x634)
[<c020c818>] (dwapb_gpio_probe) from [<c0239198>] (platform_drv_probe+0x2c/0x5c)
[<c0239198>] (platform_drv_probe) from [<c0237bd4>] (driver_probe_device+0x78/0x208)
[<c0237bd4>] (driver_probe_device) from [<c0237df0>] (__driver_attach+0x8c/0x90)
[<c0237df0>] (__driver_attach) from [<c02364b8>] (bus_for_each_dev+0x54/0x88)
[<c02364b8>] (bus_for_each_dev) from [<c023748c>] (bus_add_driver+0xd8/0x1d4)
[<c023748c>] (bus_add_driver) from [<c0238564>] (driver_register+0x78/0xf4)
[<c0238564>] (driver_register) from [<c0008884>] (do_one_initcall+0x80/0x1b8)
[<c0008884>] (do_one_initcall) from [<c052fcd4>] (kernel_init_freeable+0x170/0x240)
[<c052fcd4>] (kernel_init_freeable) from [<c03d0238>] (kernel_init+0x8/0xec)
[<c03d0238>] (kernel_init) from [<c000e578>] (ret_from_fork+0x14/0x3c)
---[ end trace 209e273f37ff62de ]---
gpiochip_add: GPIOs 0..26 (ff70a000.gpio) failed to register
gpio-dwapb ff70a000.gpio: failed to register gpiochip for /soc/gpio@ff70a000/gpio-controller@0
gpio-dwapb: probe of ff70a000.gpio failed with error -17

How are you testing this?

Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen, Alvin Aug. 28, 2014, 1:09 a.m. UTC | #2
> 
> Hi Weike,
> 
> I tried out these patches on the current master branch (v3.17-rc2-9-g68e3702)
> with a socfpga cyclone5 board.
> 
> If I apply all 3 patches, the kernel doesn't boot.
> 
> If I rebuild with only the first patch, I get only one gpio block showing up (should
> have 3 for this board) and these messages:
> 
> 
> How are you testing this?
The patches try to not change the current OF flow, and from the log message, the other two GPIO registered failed due to duplicate name.
Let me check the code to see what happen.


> 
> Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
atull Aug. 28, 2014, 3:01 p.m. UTC | #3
On Wed, 27 Aug 2014, Weike Chen wrote:

> This patch enables suspend and resume mode for the power management, and
> it is based on Josef Ahmad's previous work.
> 
> Reviewed-by: Hock Leong Kweh <hock.leong.kweh@intel.com>
> Reviewed-by: Shevchenko, Andriy <andriy.shevchenko@intel.com>
> Signed-off-by: Weike Chen <alvin.chen@intel.com>
> ---
>  drivers/gpio/gpio-dwapb.c |   67 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 67 insertions(+)
> 
> diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
> index e0ab988..1055cb3 100644
> --- a/drivers/gpio/gpio-dwapb.c
> +++ b/drivers/gpio/gpio-dwapb.c
> @@ -560,10 +560,77 @@ static const struct of_device_id dwapb_of_match[] = {
>  };
>  MODULE_DEVICE_TABLE(of, dwapb_of_match);
>  
> +#if defined CONFIG_PM_SLEEP
> +/* Store GPIO context across system-wide suspend/resume transitions */
> +static struct gpio_saved_regs {
> +	unsigned long data;
> +	unsigned long dir;
> +	unsigned long int_en;
> +	unsigned long int_mask;
> +	unsigned long int_type;
> +	unsigned long int_pol;
> +	unsigned long int_deb;
> +} saved_regs;
> +
> +static int dwapb_gpio_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
> +	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&bgc->lock, flags);
> +
> +	saved_regs.int_mask	= dwapb_read(gpio, GPIO_INTMASK);
> +	saved_regs.int_en	= dwapb_read(gpio, GPIO_INTEN);
> +	saved_regs.int_deb	= dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
> +	saved_regs.int_pol	= dwapb_read(gpio, GPIO_INT_POLARITY);
> +	saved_regs.int_type	= dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
> +	saved_regs.dir		= dwapb_read(gpio, GPIO_SWPORTA_DDR);
> +	saved_regs.data		= dwapb_read(gpio, GPIO_SWPORTA_DR);

Hello,

The DesignWare GPIO IP can be configured to have ports a, b, c, and d. So 
you will need to save and restore any ports that are present.  I think 
that *some* configurations of the IP include a register that can tell us 
how it was configured, but that register is also optional :)  I don't have 
confidence that we can read/write the registers blindly whether they are 
known to be there or not.  So you may be stuck with looking at the
device tree or platform data to know whether banks b, c, or d exist.

Alan

> +
> +	/* Mask out interrupts */
> +	dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
> +
> +	spin_unlock_irqrestore(&bgc->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int dwapb_gpio_resume(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
> +	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&bgc->lock, flags);
> +
> +	dwapb_write(gpio, GPIO_SWPORTA_DR, saved_regs.data);
> +	dwapb_write(gpio, GPIO_SWPORTA_DDR, saved_regs.dir);
> +	dwapb_write(gpio, GPIO_INTTYPE_LEVEL, saved_regs.int_type);
> +	dwapb_write(gpio, GPIO_INT_POLARITY, saved_regs.int_pol);
> +	dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, saved_regs.int_deb);
> +	dwapb_write(gpio, GPIO_INTEN, saved_regs.int_en);
> +	dwapb_write(gpio, GPIO_INTMASK, saved_regs.int_mask);
> +
> +	/* Clear out spurious interrupts */
> +	dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
> +
> +	spin_unlock_irqrestore(&bgc->lock, flags);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
> +			 dwapb_gpio_resume);
> +
>  static struct platform_driver dwapb_gpio_driver = {
>  	.driver		= {
>  		.name	= "gpio-dwapb",
>  		.owner	= THIS_MODULE,
> +		.pm	= &dwapb_gpio_pm_ops,
>  		.of_match_table = of_match_ptr(dwapb_of_match),
>  	},
>  	.probe		= dwapb_gpio_probe,
> -- 
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen, Alvin Sept. 1, 2014, 3:20 a.m. UTC | #4
> > +/* Store GPIO context across system-wide suspend/resume transitions
> > +*/ static struct gpio_saved_regs {
> > +	unsigned long data;
> > +	unsigned long dir;
> > +	unsigned long int_en;
> > +	unsigned long int_mask;
> > +	unsigned long int_type;
> > +	unsigned long int_pol;
> > +	unsigned long int_deb;
> > +} saved_regs;
> > +
> > +static int dwapb_gpio_suspend(struct device *dev) {
> > +	struct platform_device *pdev = to_platform_device(dev);
> > +	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
> > +	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&bgc->lock, flags);
> > +
> > +	saved_regs.int_mask	= dwapb_read(gpio, GPIO_INTMASK);
> > +	saved_regs.int_en	= dwapb_read(gpio, GPIO_INTEN);
> > +	saved_regs.int_deb	= dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
> > +	saved_regs.int_pol	= dwapb_read(gpio, GPIO_INT_POLARITY);
> > +	saved_regs.int_type	= dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
> > +	saved_regs.dir		= dwapb_read(gpio, GPIO_SWPORTA_DDR);
> > +	saved_regs.data		= dwapb_read(gpio, GPIO_SWPORTA_DR);
> 
> Hello,
> 
> The DesignWare GPIO IP can be configured to have ports a, b, c, and d. So you
> will need to save and restore any ports that are present.  I think that *some*
> configurations of the IP include a register that can tell us how it was configured,
> but that register is also optional :)  I don't have confidence that we can
> read/write the registers blindly whether they are known to be there or not.
> So you may be stuck with looking at the device tree or platform data to know
> whether banks b, c, or d exist.
>
From the code, the device node has one property for port index. If the index is '0', then it is port A.
So I think we can store the status according to the port index.

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij Sept. 4, 2014, 4:45 p.m. UTC | #5
On Wed, Aug 27, 2014 at 7:46 PM, Weike Chen <alvin.chen@intel.com> wrote:

> This patch enables suspend and resume mode for the power management, and
> it is based on Josef Ahmad's previous work.
>
> Reviewed-by: Hock Leong Kweh <hock.leong.kweh@intel.com>
> Reviewed-by: Shevchenko, Andriy <andriy.shevchenko@intel.com>
> Signed-off-by: Weike Chen <alvin.chen@intel.com>

(...)

> +#if defined CONFIG_PM_SLEEP

I wonder whether it's worth #ifdef:in out such things, it clutters
the place.

> +/* Store GPIO context across system-wide suspend/resume transitions */
> +static struct gpio_saved_regs {

Call the struct:

struct dwapb_context

because that is easier to understand.

> +       unsigned long data;
> +       unsigned long dir;
> +       unsigned long int_en;
> +       unsigned long int_mask;
> +       unsigned long int_type;
> +       unsigned long int_pol;
> +       unsigned long int_deb;
> +} saved_regs;

Singleton huh?

Insert this into the dynamically allocated per-port or chip struct
instead.

+       dwapb_write(gpio, GPIO_SWPORTA_DR, saved_regs.data);
+       dwapb_write(gpio, GPIO_SWPORTA_DDR, saved_regs.dir);

And port B, C, D?

This looks like a crude hack.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen, Alvin Sept. 5, 2014, 2:09 a.m. UTC | #6
PiANCj4gPiArI2lmIGRlZmluZWQgQ09ORklHX1BNX1NMRUVQDQo+IA0KPiBJIHdvbmRlciB3aGV0
aGVyIGl0J3Mgd29ydGggI2lmZGVmOmluIG91dCBzdWNoIHRoaW5ncywgaXQgY2x1dHRlcnMgdGhl
IHBsYWNlLg0KT0suIEkgd2lsbCB1c2UgJyNpZmRlZicuDQo+IA0KPiA+ICsvKiBTdG9yZSBHUElP
IGNvbnRleHQgYWNyb3NzIHN5c3RlbS13aWRlIHN1c3BlbmQvcmVzdW1lIHRyYW5zaXRpb25zDQo+
ID4gKyovIHN0YXRpYyBzdHJ1Y3QgZ3Bpb19zYXZlZF9yZWdzIHsNCj4gDQo+IENhbGwgdGhlIHN0
cnVjdDoNCj4gDQo+IHN0cnVjdCBkd2FwYl9jb250ZXh0DQo+IA0KPiBiZWNhdXNlIHRoYXQgaXMg
ZWFzaWVyIHRvIHVuZGVyc3RhbmQuDQo+IA0KT0suDQoNCj4gPiArICAgICAgIHVuc2lnbmVkIGxv
bmcgZGF0YTsNCj4gPiArICAgICAgIHVuc2lnbmVkIGxvbmcgZGlyOw0KPiA+ICsgICAgICAgdW5z
aWduZWQgbG9uZyBpbnRfZW47DQo+ID4gKyAgICAgICB1bnNpZ25lZCBsb25nIGludF9tYXNrOw0K
PiA+ICsgICAgICAgdW5zaWduZWQgbG9uZyBpbnRfdHlwZTsNCj4gPiArICAgICAgIHVuc2lnbmVk
IGxvbmcgaW50X3BvbDsNCj4gPiArICAgICAgIHVuc2lnbmVkIGxvbmcgaW50X2RlYjsNCj4gPiAr
fSBzYXZlZF9yZWdzOw0KPiANCj4gU2luZ2xldG9uIGh1aD8NCj4gDQo+IEluc2VydCB0aGlzIGlu
dG8gdGhlIGR5bmFtaWNhbGx5IGFsbG9jYXRlZCBwZXItcG9ydCBvciBjaGlwIHN0cnVjdCBpbnN0
ZWFkLg0KPiANCkhvdyBhYm91dCB0aGUgZm9sbG93aW5nPw0KDQpzdGF0aWMgc3RydWN0IGR3YXBi
X2NvbnRleHQgew0KCXUzMiBkYXRhW0RXQVBCX01BWF9QT1JUU107DQoJdTMyIGRpcltEV0FQQl9N
QVhfUE9SVFNdOw0KCXUzMiBleHRbRFdBUEJfTUFYX1BPUlRTXTsNCgl1MzIgaW50X2VuOw0KCXUz
MiBpbnRfbWFzazsNCgl1MzIgaW50X3R5cGU7DQoJdTMyIGludF9wb2w7DQoJdTMyIGludF9kZWI7
DQp9IGR3YXBiX2NvbnRleHQ7DQoNClNpbmNlIG9ubHkgcG9ydEEgY2FuIHN1cHBvcnQgaXJxLCBh
bmQgdGhlIGlycSByZWxhdGVkIHJlZ2lzdGVycyBhcmUgb25seSBmb3IgcG9ydEEuIENvbXBhcmlu
ZyB0byBhbGxvY2F0ZSBmb3IgZWFjaCBwb3J0DQpkeW5hbWljYWxseSwgaXQgaXMgbW9yZSBkaXJl
Y3RseSBhbmQgZWFzeSB0byB1bmRlcnN0YW5kLiANCg0KDQo+ICsgICAgICAgZHdhcGJfd3JpdGUo
Z3BpbywgR1BJT19TV1BPUlRBX0RSLCBzYXZlZF9yZWdzLmRhdGEpOw0KPiArICAgICAgIGR3YXBi
X3dyaXRlKGdwaW8sIEdQSU9fU1dQT1JUQV9ERFIsIHNhdmVkX3JlZ3MuZGlyKTsNCj4gDQo+IEFu
ZCBwb3J0IEIsIEMsIEQ/DQo+IA0KPiBUaGlzIGxvb2tzIGxpa2UgYSBjcnVkZSBoYWNrLg0KSSB3
aWxsIGFkZCBwb3J0IEIsIEMsIEQuDQo+IA0KPiBZb3VycywNCj4gTGludXMgV2FsbGVpag0K
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij Sept. 5, 2014, 8 a.m. UTC | #7
On Fri, Sep 5, 2014 at 4:09 AM, Chen, Alvin <alvin.chen@intel.com> wrote:

>> > +       unsigned long data;
>> > +       unsigned long dir;
>> > +       unsigned long int_en;
>> > +       unsigned long int_mask;
>> > +       unsigned long int_type;
>> > +       unsigned long int_pol;
>> > +       unsigned long int_deb;
>> > +} saved_regs;
>>
>> Singleton huh?
>>
>> Insert this into the dynamically allocated per-port or chip struct instead.
>>
> How about the following?
>
> static struct dwapb_context {
>         u32 data[DWAPB_MAX_PORTS];
>         u32 dir[DWAPB_MAX_PORTS];
>         u32 ext[DWAPB_MAX_PORTS];
>         u32 int_en;
>         u32 int_mask;
>         u32 int_type;
>         u32 int_pol;
>         u32 int_deb;
> } dwapb_context;

NO because this is still a singleton variable. Put it into the
dynamically allocated structs.

> Comparing to allocate for each port
> dynamically, it is more directly and easy to understand.

No, I disagree. The overall design pattern in the kernel is to
allocate all state containers dynamically.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chen, Alvin Sept. 5, 2014, 8:20 a.m. UTC | #8
PiA+Pg0KPiA+PiBJbnNlcnQgdGhpcyBpbnRvIHRoZSBkeW5hbWljYWxseSBhbGxvY2F0ZWQgcGVy
LXBvcnQgb3IgY2hpcCBzdHJ1Y3QgaW5zdGVhZC4NCj4gPj4NCj4gPiBIb3cgYWJvdXQgdGhlIGZv
bGxvd2luZz8NCj4gPg0KPiA+IHN0YXRpYyBzdHJ1Y3QgZHdhcGJfY29udGV4dCB7DQo+ID4gICAg
ICAgICB1MzIgZGF0YVtEV0FQQl9NQVhfUE9SVFNdOw0KPiA+ICAgICAgICAgdTMyIGRpcltEV0FQ
Ql9NQVhfUE9SVFNdOw0KPiA+ICAgICAgICAgdTMyIGV4dFtEV0FQQl9NQVhfUE9SVFNdOw0KPiA+
ICAgICAgICAgdTMyIGludF9lbjsNCj4gPiAgICAgICAgIHUzMiBpbnRfbWFzazsNCj4gPiAgICAg
ICAgIHUzMiBpbnRfdHlwZTsNCj4gPiAgICAgICAgIHUzMiBpbnRfcG9sOw0KPiA+ICAgICAgICAg
dTMyIGludF9kZWI7DQo+ID4gfSBkd2FwYl9jb250ZXh0Ow0KPiANCj4gTk8gYmVjYXVzZSB0aGlz
IGlzIHN0aWxsIGEgc2luZ2xldG9uIHZhcmlhYmxlLiBQdXQgaXQgaW50byB0aGUgZHluYW1pY2Fs
bHkgYWxsb2NhdGVkDQo+IHN0cnVjdHMuDQo+IA0KPiA+IENvbXBhcmluZyB0byBhbGxvY2F0ZSBm
b3IgZWFjaCBwb3J0DQo+ID4gZHluYW1pY2FsbHksIGl0IGlzIG1vcmUgZGlyZWN0bHkgYW5kIGVh
c3kgdG8gdW5kZXJzdGFuZC4NCj4gDQo+IE5vLCBJIGRpc2FncmVlLiBUaGUgb3ZlcmFsbCBkZXNp
Z24gcGF0dGVybiBpbiB0aGUga2VybmVsIGlzIHRvIGFsbG9jYXRlIGFsbCBzdGF0ZQ0KPiBjb250
YWluZXJzIGR5bmFtaWNhbGx5Lg0KPiANCk9LLiBQbGVhc2UgYWxzbyBoZWxwIHJldmlldyB0aGUg
djIgSSBqdXN0IHNlbnQgb3V0LCBhbmQgYWZ0ZXIgZ2V0dGluZyBtb3JlIGZlZWRiYWNrcywgSSB3
aWxsIGltcHJvdmUgdGhpcyBwYXJ0IGluIHRoZSBuZXh0IHZlcnNpb24gdG9nZXRoZXIuDQoNCg0K
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index e0ab988..1055cb3 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -560,10 +560,77 @@  static const struct of_device_id dwapb_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dwapb_of_match);
 
+#if defined CONFIG_PM_SLEEP
+/* Store GPIO context across system-wide suspend/resume transitions */
+static struct gpio_saved_regs {
+	unsigned long data;
+	unsigned long dir;
+	unsigned long int_en;
+	unsigned long int_mask;
+	unsigned long int_type;
+	unsigned long int_pol;
+	unsigned long int_deb;
+} saved_regs;
+
+static int dwapb_gpio_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bgc->lock, flags);
+
+	saved_regs.int_mask	= dwapb_read(gpio, GPIO_INTMASK);
+	saved_regs.int_en	= dwapb_read(gpio, GPIO_INTEN);
+	saved_regs.int_deb	= dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
+	saved_regs.int_pol	= dwapb_read(gpio, GPIO_INT_POLARITY);
+	saved_regs.int_type	= dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
+	saved_regs.dir		= dwapb_read(gpio, GPIO_SWPORTA_DDR);
+	saved_regs.data		= dwapb_read(gpio, GPIO_SWPORTA_DR);
+
+	/* Mask out interrupts */
+	dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
+
+	spin_unlock_irqrestore(&bgc->lock, flags);
+
+	return 0;
+}
+
+static int dwapb_gpio_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+	struct bgpio_chip *bgc	= &gpio->ports[0].bgc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bgc->lock, flags);
+
+	dwapb_write(gpio, GPIO_SWPORTA_DR, saved_regs.data);
+	dwapb_write(gpio, GPIO_SWPORTA_DDR, saved_regs.dir);
+	dwapb_write(gpio, GPIO_INTTYPE_LEVEL, saved_regs.int_type);
+	dwapb_write(gpio, GPIO_INT_POLARITY, saved_regs.int_pol);
+	dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, saved_regs.int_deb);
+	dwapb_write(gpio, GPIO_INTEN, saved_regs.int_en);
+	dwapb_write(gpio, GPIO_INTMASK, saved_regs.int_mask);
+
+	/* Clear out spurious interrupts */
+	dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
+
+	spin_unlock_irqrestore(&bgc->lock, flags);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
+			 dwapb_gpio_resume);
+
 static struct platform_driver dwapb_gpio_driver = {
 	.driver		= {
 		.name	= "gpio-dwapb",
 		.owner	= THIS_MODULE,
+		.pm	= &dwapb_gpio_pm_ops,
 		.of_match_table = of_match_ptr(dwapb_of_match),
 	},
 	.probe		= dwapb_gpio_probe,