Message ID | 1409161588-19417-4-git-send-email-alvin.chen@intel.com |
---|---|
State | Superseded, archived |
Headers | show |
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
> > 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
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
> > +/* 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
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
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
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
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 --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,