Skip to content

Commit de0c9a6

Browse files
authored
Merge pull request #11 from VoodooI2C/suspend-resume
Fix Suspend/Resume IRQ issue
2 parents 0305497 + 86a71e2 commit de0c9a6

File tree

2 files changed

+71
-31
lines changed

2 files changed

+71
-31
lines changed

VoodooGPIO/VoodooGPIO.cpp

+68-31
Original file line numberDiff line numberDiff line change
@@ -453,14 +453,16 @@ void VoodooGPIO::intel_pinctrl_pm_init() {
453453
for (int i = 0; i < ncommunities; i++) {
454454
intel_community *community = &communities[i];
455455

456-
context.communities[i].intmask = IONew(UInt32, community->ngpps);;
456+
context.communities[i].intmask = IONew(UInt32, community->ngpps);
457+
context.communities[i].hostown = IONew(UInt32, community->ngpps);
457458
}
458459
}
459460

460461
void VoodooGPIO::intel_pinctrl_pm_release() {
461462
for (int i = 0; i < ncommunities; i++) {
462463
intel_community *community = &communities[i];
463464
IOSafeDeleteNULL(context.communities[i].intmask, UInt32, community->ngpps);
465+
IOSafeDeleteNULL(context.communities[i].hostown, UInt32, community->ngpps);
464466
}
465467

466468
IOSafeDeleteNULL(context.communities, intel_community_context, ncommunities);
@@ -500,11 +502,15 @@ void VoodooGPIO::intel_pinctrl_suspend() {
500502
struct intel_community_context *communityContexts = context.communities;
501503
for (int i = 0; i < ncommunities; i++) {
502504
struct intel_community *community = &communities[i];
503-
504-
IOVirtualAddress base = community->regs + community->ie_offset;
505-
506-
for (unsigned gpp = 0; gpp < community->ngpps; gpp++)
505+
IOVirtualAddress base = 0;
506+
507+
base = community->regs + community->ie_offset;
508+
for (unsigned int gpp = 0; gpp < community->ngpps; gpp++)
507509
communityContexts[i].intmask[gpp] = readl(base + gpp * 4);
510+
511+
base = community->regs + community->hostown_offset;
512+
for (unsigned int gpp = 0; gpp < community->ngpps; gpp++)
513+
communityContexts[i].hostown[gpp] = readl(base + gpp * 4);
508514
}
509515
}
510516

@@ -521,6 +527,37 @@ void VoodooGPIO::intel_gpio_irq_init() {
521527
}
522528
}
523529

530+
UInt32 VoodooGPIO::intel_gpio_is_requested(int base, unsigned int size) {
531+
UInt32 requested = 0;
532+
533+
for (unsigned int pin_offset = 0; pin_offset < size; pin_offset++) {
534+
UInt32 gpio_pin = base + pin_offset;
535+
SInt32 hw_pin = intel_gpio_to_pin(gpio_pin, nullptr, nullptr);
536+
if (hw_pin < 0)
537+
continue;
538+
539+
for (unsigned int registered_idx = 0; registered_idx < registered_pin_list->getCount(); registered_idx++) {
540+
OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(registered_idx));
541+
if (registered_pin && registered_pin->unsigned32BitValue() == hw_pin) {
542+
requested |= BIT(pin_offset);
543+
break;
544+
}
545+
}
546+
}
547+
548+
return requested;
549+
}
550+
551+
UInt32 VoodooGPIO::intel_gpio_update_pad_mode(IOVirtualAddress hostown, UInt32 mask, UInt32 value) {
552+
UInt32 curr, updated;
553+
554+
curr = readl(hostown);
555+
updated = (curr & ~mask) | (value & mask);
556+
writel(updated, hostown);
557+
558+
return curr;
559+
}
560+
524561
void VoodooGPIO::intel_pinctrl_resume() {
525562
/* Mask all interrupts */
526563
intel_gpio_irq_init();
@@ -563,12 +600,28 @@ void VoodooGPIO::intel_pinctrl_resume() {
563600
struct intel_community_context *communityContexts = context.communities;
564601
for (int i = 0; i < ncommunities; i++) {
565602
struct intel_community *community = &communities[i];
603+
IOVirtualAddress base = 0;
566604

567-
IOVirtualAddress base = communities->regs + communities->ie_offset;
568-
569-
for (unsigned gpp = 0; gpp < community->ngpps; gpp++) {
605+
base = communities->regs + communities->ie_offset;
606+
for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) {
570607
writel(communityContexts[i].intmask[gpp], base + gpp * 4);
571608
}
609+
610+
base = community->regs + community->hostown_offset;
611+
for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) {
612+
const struct intel_padgroup *padgrp = &community->gpps[gpp];
613+
UInt32 requested = 0, value = 0;
614+
UInt32 saved = communityContexts[i].hostown[gpp];
615+
616+
if (padgrp->gpio_base < 0)
617+
continue;
618+
619+
requested = intel_gpio_is_requested(padgrp->gpio_base, padgrp->size);
620+
value = intel_gpio_update_pad_mode(base + gpp * 4, requested, saved);
621+
if ((value ^ saved) & requested) {
622+
IOLog("%s::restore hostown %d/%u %#8x->%#8x\n", getName(), i, gpp, value, saved);
623+
}
624+
}
572625
}
573626
}
574627

@@ -746,37 +799,19 @@ void VoodooGPIO::stop(IOService *provider) {
746799
}
747800

748801
IOReturn VoodooGPIO::setPowerState(unsigned long powerState, IOService *whatDevice) {
802+
if (whatDevice != this)
803+
return kIOPMAckImplied;
804+
749805
if (powerState == 0) {
750806
controllerIsAwake = false;
751807

752-
for (int i = 0; i < ncommunities; i++) {
753-
struct intel_community *community = &communities[i];
754-
for (int j = 0; j < community->npins; j++) {
755-
OSObject *pinInterruptOwner = community->pinInterruptActionOwners[j];
756-
if (pinInterruptOwner) {
757-
int pin = community->pin_base + j;
758-
intel_gpio_irq_mask_unmask(pin, true);
759-
}
760-
}
761-
}
762-
808+
intel_pinctrl_suspend();
763809
IOLog("%s::Going to Sleep!\n", getName());
764810
} else {
765811
if (!controllerIsAwake) {
766812
controllerIsAwake = true;
767813

768-
for (int i = 0; i < ncommunities; i++) {
769-
struct intel_community *community = &communities[i];
770-
for (int j = 0; j < community->npins; j++) {
771-
OSObject *pinInterruptOwner = community->pinInterruptActionOwners[j];
772-
if (pinInterruptOwner) {
773-
int pin = community->pin_base + j;
774-
intel_gpio_irq_set_type(pin, community->interruptTypes[j]);
775-
intel_gpio_irq_mask_unmask(pin, false);
776-
}
777-
}
778-
}
779-
814+
intel_pinctrl_resume();
780815
IOLog("%s::Woke up from Sleep!\n", getName());
781816
} else {
782817
IOLog("%s::GPIO Controller is already awake! Not reinitializing.\n", getName());
@@ -931,6 +966,8 @@ IOReturn VoodooGPIO::unregisterInterrupt(int pin) {
931966
if (hw_pin < 0)
932967
return kIOReturnNoInterrupt;
933968

969+
IOLog("%s::Unregistering hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin);
970+
934971
intel_gpio_irq_mask_unmask(hw_pin, true);
935972

936973
unsigned communityidx = hw_pin - community->pin_base;

VoodooGPIO/VoodooGPIO.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ struct intel_pad_context {
151151

152152
struct intel_community_context {
153153
uint32_t *intmask;
154+
uint32_t *hostown;
154155
};
155156

156157
struct intel_pinctrl_context {
@@ -241,6 +242,8 @@ class VoodooGPIO : public IOService {
241242
void intel_pinctrl_pm_release();
242243
void intel_pinctrl_suspend();
243244
void intel_gpio_irq_init();
245+
UInt32 intel_gpio_is_requested(int base, unsigned int size);
246+
UInt32 intel_gpio_update_pad_mode(IOVirtualAddress hostown, UInt32 mask, UInt32 value);
244247
void intel_pinctrl_resume();
245248

246249
void intel_gpio_community_irq_handler(struct intel_community *community, bool *firstdelay);

0 commit comments

Comments
 (0)