k1:hall:support separating wake-up interrupts from normal work interrupts for edge-detect wakeup function

Change-Id: I17a867c0595fa07ad17ca7c396f2272ce8f61b10
This commit is contained in:
Nell
2024-10-25 19:06:54 +08:00
committed by zhangmeng
parent a51f67c4e1
commit 7b328bfcf4
5 changed files with 148 additions and 11 deletions

View File

@@ -140,11 +140,11 @@
spacemit_lid:spacemit_lid {
compatible = "spacemit,k1x-lid";
lid-gpios = <&gpio 74 0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hall_wakeup>;
interrupt-parent = <&pinctrl>;
interrupts = <300>;
lid-gpios = <&gpio 74 0>;
interrupts-extended = <&gpio 74 1
&pinctrl 300>;
};
rf_pwrseq: rf-pwrseq {

View File

@@ -212,6 +212,66 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
}
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
#ifdef CONFIG_SOC_SPACEMIT_K1X
static int __dev_pm_set_dedicated_wake_irq_spacemit(struct device *dev, int irq, unsigned int flag, int trigger_type)
{
struct wake_irq *wirq;
int err;
if (irq < 0)
return -EINVAL;
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
if (!wirq)
return -ENOMEM;
wirq->name = kasprintf(GFP_KERNEL, "%s:wakeup", dev_name(dev));
if (!wirq->name) {
err = -ENOMEM;
goto err_free;
}
wirq->dev = dev;
wirq->irq = irq;
/* Prevent deferred spurious wakeirqs with disable_irq_nosync() */
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
/*
* Consumer device may need to power up and restore state
* so we use a threaded irq.
*/
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN | trigger_type,
wirq->name, wirq);
if (err)
goto err_free_name;
err = dev_pm_attach_wake_irq(dev, wirq);
if (err)
goto err_free_irq;
wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED | flag;
return err;
err_free_irq:
free_irq(irq, wirq);
err_free_name:
kfree(wirq->name);
err_free:
kfree(wirq);
return err;
}
int dev_pm_set_dedicated_wake_irq_spacemit(struct device *dev, int irq, int trigger_type)
{
return __dev_pm_set_dedicated_wake_irq_spacemit(dev, irq, 0, trigger_type);
}
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq_spacemit);
#endif
/**
* dev_pm_set_dedicated_wake_irq_reverse - Request a dedicated wake-up interrupt
* with reverse enable ordering

View File

@@ -1488,6 +1488,57 @@ static int pcs_irq_set_wake(struct irq_data *d, unsigned int state)
return 0;
}
#ifdef CONFIG_SOC_SPACEMIT_K1X
static inline void _pcs_irq_set_type(struct pcs_soc_data *pcs_soc,
int irq, int flow_type)
{
struct pcs_device *pcs;
struct list_head *pos;
unsigned mask;
pcs = container_of(pcs_soc, struct pcs_device, socdata);
list_for_each(pos, &pcs->irqs) {
struct pcs_interrupt *pcswi;
unsigned soc_mask;
pcswi = list_entry(pos, struct pcs_interrupt, node);
if (irq != pcswi->irq)
continue;
soc_mask = pcs_soc->irq_enable_mask;
raw_spin_lock(&pcs->lock);
mask = pcs->read(pcswi->reg);
if (flow_type == IRQ_TYPE_EDGE_RISING) {
mask |= (1 << EDGE_RISE_EN);
} else {
mask &= ~(1 << EDGE_RISE_EN);
}
if (flow_type == IRQ_TYPE_EDGE_FALLING) {
mask |= (1 << EDGE_FALL_EN);
} else {
mask &= ~(1 << EDGE_FALL_EN);
}
pcs->write(mask, pcswi->reg);
/* flush posted write */
mask = pcs->read(pcswi->reg);
raw_spin_unlock(&pcs->lock);
}
}
static int pcs_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
struct pcs_soc_data *pcs_soc = irq_data_get_irq_chip_data(d);
_pcs_irq_set_type(pcs_soc, d->irq, flow_type);
return 0;
}
#endif
/**
* pcs_irq_handle() - common interrupt handler
* @pcs_soc: SoC specific settings
@@ -1630,6 +1681,10 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs,
pcs->chip.irq_mask = pcs_irq_mask;
pcs->chip.irq_unmask = pcs_irq_unmask;
pcs->chip.irq_set_wake = pcs_irq_set_wake;
#ifdef CONFIG_SOC_SPACEMIT_K1X
pcs->chip.flags = IRQCHIP_SKIP_SET_WAKE;
pcs->chip.irq_set_type = pcs_irq_set_type;
#endif
if (PCS_QUIRK_HAS_SHARED_IRQ) {
int res;
@@ -2030,7 +2085,7 @@ static int pcs_probe(struct platform_device *pdev)
dev_info(pcs->dev, "%i pins, size %u\n", pcs->desc.npins, pcs->size);
#ifdef CONFIG_SOC_SPACEMIT_K1X
dev_pm_set_wake_irq(&pdev->dev, pcs->socdata.irq );
dev_pm_set_wake_irq(&pdev->dev, pcs->socdata.irq);
device_init_wakeup(&pdev->dev, true);
#endif

View File

@@ -13,12 +13,14 @@
#include <linux/pm_wakeirq.h>
#include <linux/gpio/consumer.h>
#include <linux/property.h>
#include <linux/pm_wakeirq.h>
#include <linux/of.h>
struct _hall {
int irq;
struct device *dev;
struct input_dev *input;
struct gpio_desc *gpio;
int wakeup_irq, normal_irq;
};
static irqreturn_t hall_wakeup_detect(int irq, void *arg)
@@ -27,6 +29,9 @@ static irqreturn_t hall_wakeup_detect(int irq, void *arg)
struct _hall *hall = (struct _hall *)arg;
state = gpiod_get_value(hall->gpio);
pm_wakeup_event(hall->dev, 0);
input_report_switch(hall->input, SW_LID, !state);
input_sync(hall->input);
@@ -45,24 +50,27 @@ static int spacemit_lid_probe(struct platform_device *pdev)
hall->gpio = devm_gpiod_get(&pdev->dev, "lid", GPIOD_IN);
if (IS_ERR_OR_NULL(hall->gpio)) {
pr_err("get gpio error\n");
return PTR_ERR(hall->gpio);
}
hall->irq = platform_get_irq(pdev, 0);
if (hall->irq < 0)
hall->normal_irq = platform_get_irq(pdev, 0);
if (hall->normal_irq < 0)
return -EINVAL;
error = devm_request_any_context_irq(&pdev->dev, hall->irq,
hall->wakeup_irq = platform_get_irq(pdev, 1);
if (hall->wakeup_irq < 0) {
return -EINVAL;
}
error = devm_request_irq(&pdev->dev, hall->normal_irq,
hall_wakeup_detect,
IRQF_ONESHOT | IRQF_TRIGGER_NONE,
IRQF_NO_SUSPEND | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"hall-detect", (void *)hall);
if (error) {
pr_err("request hall pinctrl dectect failed\n");
return -EINVAL;
}
input = devm_input_allocate_device(&pdev->dev);
if (!input)
return -ENOMEM;
@@ -73,6 +81,7 @@ static int spacemit_lid_probe(struct platform_device *pdev)
input_set_drvdata(input, hall);
hall->dev = &pdev->dev;
hall->input = input;
error = input_register_device(input);
@@ -81,6 +90,9 @@ static int spacemit_lid_probe(struct platform_device *pdev)
return error;
}
dev_pm_set_dedicated_wake_irq_spacemit(&pdev->dev, hall->wakeup_irq, IRQ_TYPE_EDGE_RISING);
device_init_wakeup(&pdev->dev, true);
return 0;
}

View File

@@ -8,6 +8,9 @@
extern int dev_pm_set_wake_irq(struct device *dev, int irq);
extern int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq);
#ifdef CONFIG_SOC_SPACEMIT_K1X
extern int dev_pm_set_dedicated_wake_irq_spacemit(struct device *dev, int irq, int trigger_tyep);
#endif
extern int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq);
extern void dev_pm_clear_wake_irq(struct device *dev);
@@ -23,6 +26,13 @@ static inline int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
return 0;
}
#ifdef CONFIG_SOC_SPACEMIT_K1X
static inline int dev_pm_set_dedicated_wake_irq_spacemit(struct device *dev, int irq)
{
return 0;
}
#endif
static inline int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq)
{
return 0;