#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/task.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/fdt/spmivar.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/fdt.h>
#define PON_RT_STS 0x10
#define PON_PMK8350_KPDPWR_N_SET (1U << 7)
struct qcpon_softc {
struct device sc_dev;
int sc_node;
spmi_tag_t sc_tag;
int8_t sc_sid;
uint16_t sc_addr;
void *sc_pwrkey_ih;
uint32_t sc_last_sts;
};
int qcpon_match(struct device *, void *, void *);
void qcpon_attach(struct device *, struct device *, void *);
int qcpon_pwrkey_intr(void *);
const struct cfattach qcpon_ca = {
sizeof(struct qcpon_softc), qcpon_match, qcpon_attach
};
struct cfdriver qcpon_cd = {
NULL, "qcpon", DV_DULL
};
int
qcpon_match(struct device *parent, void *match, void *aux)
{
struct spmi_attach_args *saa = aux;
return (OF_is_compatible(saa->sa_node, "qcom,pm8998-pon") ||
OF_is_compatible(saa->sa_node, "qcom,pmk8350-pon"));
}
void
qcpon_attach(struct device *parent, struct device *self, void *aux)
{
struct spmi_attach_args *saa = aux;
struct qcpon_softc *sc = (struct qcpon_softc *)self;
uint32_t reg[2];
int node;
if (OF_getpropintarray(saa->sa_node, "reg",
reg, sizeof(reg)) != sizeof(reg)) {
printf(": can't find registers\n");
return;
}
sc->sc_node = saa->sa_node;
sc->sc_tag = saa->sa_tag;
sc->sc_sid = saa->sa_sid;
sc->sc_addr = reg[0];
printf("\n");
for (node = OF_child(saa->sa_node); node; node = OF_peer(node)) {
if (OF_is_compatible(node, "qcom,pmk8350-pwrkey")) {
sc->sc_pwrkey_ih = fdt_intr_establish(node,
IPL_BIO | IPL_WAKEUP, qcpon_pwrkey_intr, sc,
sc->sc_dev.dv_xname);
if (sc->sc_pwrkey_ih == NULL) {
printf("%s: can't establish interrupt\n",
sc->sc_dev.dv_xname);
continue;
}
#ifdef SUSPEND
device_register_wakeup(&sc->sc_dev);
#endif
}
}
}
int
qcpon_pwrkey_intr(void *arg)
{
struct qcpon_softc *sc = arg;
#ifdef SUSPEND
extern int cpu_suspended;
#endif
uint32_t sts;
int error;
#ifdef SUSPEND
if (cpu_suspended) {
cpu_suspended = 0;
return 1;
}
#endif
error = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL,
sc->sc_addr + PON_RT_STS, &sts, sizeof(sts));
if (error)
return 0;
if ((sc->sc_last_sts & PON_PMK8350_KPDPWR_N_SET) &&
(sts & PON_PMK8350_KPDPWR_N_SET) == 0)
powerbutton_event();
sc->sc_last_sts = sts;
return 1;
}