rv1126-uboot/drivers/input/rk8xx_pwrkey.c

289 lines
7.4 KiB
C

/*
* (C) Copyright 2017 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <key.h>
#include <linux/input.h>
#include <power/pmic.h>
#include <power/rk8xx_pmic.h>
#include <irq-generic.h>
#include <asm/arch/periph.h>
#include <dm/pinctrl.h>
#define RK817_GPIO_INT_CFG 0xfe
#define RK817_INT_STS_REG0 0xf8
#define RK817_INT_MSK_REG0 0xf9
#define RK817_INT_STS_REG1 0xfa
#define RK817_INT_MSK_REG1 0xfb
#define RK817_INT_STS_REG2 0xfc
#define RK817_INT_MSK_REG2 0xfd
#define RK817_PWRON_RISE_INT (1 << 1)
#define RK817_PWRON_FALL_INT (1 << 0)
#define RK817_INT_POL_MSK BIT(1)
#define RK816_INT_STS_REG1 0x49
#define RK816_INT_MSK_REG1 0x4a
#define RK816_INT_STS_REG2 0x4c
#define RK816_INT_MSK_REG2 0x4d
#define RK816_INT_STS_REG3 0x4e
#define RK816_INT_MSK_REG3 0x4f
#define RK816_PWRON_RISE_INT (1 << 6)
#define RK816_PWRON_FALL_INT (1 << 5)
#define RK805_INT_STS_REG 0x4c
#define RK805_INT_MSK_REG 0x4d
#define RK805_PWRON_RISE_INT (1 << 0)
#define RK805_PWRON_FALL_INT (1 << 7)
struct reg_data {
u8 reg;
u8 val;
};
struct rk8xx_key_priv {
u8 int_sts_reg;
u8 int_msk_reg;
u8 pwron_rise_int;
u8 pwron_fall_int;
struct reg_data *init_reg;
u32 init_reg_num;
struct reg_data *irq_reg;
u32 irq_reg_num;
};
static struct reg_data rk817_init_reg[] = {
/* only enable rise/fall interrupt */
{ RK817_INT_MSK_REG0, 0xfc },
{ RK817_INT_MSK_REG1, 0xff },
{ RK817_INT_MSK_REG2, 0xff },
/* clear all interrupt states */
{ RK817_INT_STS_REG0, 0xff },
{ RK817_INT_STS_REG1, 0xff },
{ RK817_INT_STS_REG2, 0xff },
/* pmic_int active low */
{ RK817_GPIO_INT_CFG, 0x20 },
};
static struct reg_data rk817_irq_reg[] = {
/* clear all interrupt states */
{ RK817_INT_STS_REG0, 0xff },
{ RK817_INT_STS_REG1, 0xff },
{ RK817_INT_STS_REG2, 0xff },
};
static struct reg_data rk816_init_reg[] = {
/* only enable rise/fall interrupt */
{ RK816_INT_MSK_REG1, 0x9f },
{ RK816_INT_MSK_REG2, 0xff },
{ RK816_INT_MSK_REG3, 0xff },
/* clear all interrupt states */
{ RK816_INT_STS_REG1, 0xff },
{ RK816_INT_STS_REG2, 0xff },
{ RK816_INT_STS_REG3, 0xff },
};
static struct reg_data rk816_irq_reg[] = {
/* clear all interrupt states */
{ RK816_INT_STS_REG1, 0xff },
{ RK816_INT_STS_REG2, 0xff },
{ RK816_INT_STS_REG3, 0xff },
};
static struct reg_data rk805_irq_reg[] = {
/* clear all interrupt states */
{ RK805_INT_STS_REG, 0xff },
};
static struct reg_data rk805_init_reg[] = {
/* only enable rise/fall interrupt */
{ RK805_INT_MSK_REG, 0x7e },
/* clear all interrupt states */
{ RK805_INT_STS_REG, 0xff },
};
static int rk8xx_pwrkey_read(struct udevice *dev, int code)
{
struct input_key *key = dev_get_platdata(dev);
u32 report = KEY_NOT_EXIST;
if (key->code != code)
goto out;
debug("%s: long key ms: %llu\n",
__func__, key->up_t - key->down_t);
if ((key->up_t > key->down_t) &&
(key->up_t - key->down_t) >= KEY_LONG_DOWN_MS) {
key->up_t = 0;
key->down_t = 0;
report = KEY_PRESS_LONG_DOWN;
printf("'%s' key long pressed down\n", key->name);
} else if (key->down_t &&
key_get_timer(key->down_t) >= KEY_LONG_DOWN_MS) {
key->up_t = 0;
key->down_t = 0;
report = KEY_PRESS_LONG_DOWN;
printf("'%s' key long pressed down(hold)\n", key->name);
} else if ((key->up_t > key->down_t) &&
(key->up_t - key->down_t) < KEY_LONG_DOWN_MS) {
key->up_t = 0;
key->down_t = 0;
report = KEY_PRESS_DOWN;
printf("'%s' key pressed down\n", key->name);
} else {
report = KEY_PRESS_NONE;
}
out:
return report;
}
static void pwrkey_irq_handler(int irq, void *data)
{
struct udevice *dev = data;
struct rk8xx_key_priv *priv = dev_get_priv(dev);
struct input_key *key = dev_get_platdata(dev);
int ret, val, i;
debug("%s: irq = %d\n", __func__, irq);
/* read status */
val = pmic_reg_read(dev->parent, priv->int_sts_reg);
if (val < 0) {
printf("%s: i2c read failed, ret=%d\n", __func__, val);
return;
}
/* fall event */
if (val & priv->pwron_fall_int) {
key->down_t = key_get_timer(0);
debug("%s: key down: %llu ms\n", __func__, key->down_t);
}
/* rise event */
if (val & priv->pwron_rise_int) {
key->up_t = key_get_timer(0);
debug("%s: key up: %llu ms\n", __func__, key->up_t);
}
/* clear intertup */
for (i = 0; i < priv->irq_reg_num; i++) {
ret = pmic_reg_write(dev->parent,
priv->irq_reg[i].reg,
priv->irq_reg[i].val);
if (ret < 0) {
printf("%s: i2c write reg 0x%x failed, ret=%d\n",
__func__, priv->irq_reg[i].reg, ret);
}
debug("%s: reg[0x%x] = 0x%x\n", __func__, priv->irq_reg[i].reg,
pmic_reg_read(dev->parent, priv->irq_reg[i].reg));
}
}
static int pwrkey_interrupt_init(struct udevice *dev)
{
struct input_key *key = dev_get_platdata(dev);
u32 interrupt[2], phandle;
int irq, ret;
phandle = dev_read_u32_default(dev->parent, "interrupt-parent", -1);
if (phandle < 0) {
printf("failed get 'interrupt-parent', ret=%d\n", phandle);
return phandle;
}
ret = dev_read_u32_array(dev->parent, "interrupts", interrupt, 2);
if (ret) {
printf("failed get 'interrupt', ret=%d\n", ret);
return ret;
}
key->name = "pwrkey";
key->code = KEY_POWER;
irq = phandle_gpio_to_irq(phandle, interrupt[0]);
irq_install_handler(irq, pwrkey_irq_handler, dev);
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
irq_handler_enable(irq);
return 0;
}
static const struct dm_key_ops key_ops = {
.name = "rk8xx-pwrkey",
.read = rk8xx_pwrkey_read,
};
static int rk8xx_pwrkey_probe(struct udevice *dev)
{
struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
struct rk8xx_key_priv *priv = dev_get_priv(dev);
int ret, i;
switch (rk8xx->variant) {
case RK805_ID:
priv->int_sts_reg = RK805_INT_STS_REG;
priv->int_msk_reg = RK805_INT_MSK_REG;
priv->pwron_rise_int = RK805_PWRON_RISE_INT;
priv->pwron_fall_int = RK805_PWRON_FALL_INT;
priv->init_reg = rk805_init_reg;
priv->init_reg_num = ARRAY_SIZE(rk805_init_reg);
priv->irq_reg = rk805_irq_reg;
priv->irq_reg_num = ARRAY_SIZE(rk805_irq_reg);
break;
case RK816_ID:
priv->int_sts_reg = RK816_INT_STS_REG1;
priv->int_msk_reg = RK816_INT_MSK_REG1;
priv->pwron_rise_int = RK816_PWRON_RISE_INT;
priv->pwron_fall_int = RK816_PWRON_FALL_INT;
priv->init_reg = rk816_init_reg;
priv->init_reg_num = ARRAY_SIZE(rk816_init_reg);
priv->irq_reg = rk816_irq_reg;
priv->irq_reg_num = ARRAY_SIZE(rk816_irq_reg);
break;
case RK817_ID:
priv->int_sts_reg = RK817_INT_STS_REG0;
priv->int_msk_reg = RK817_INT_MSK_REG0;
priv->pwron_rise_int = RK817_PWRON_RISE_INT;
priv->pwron_fall_int = RK817_PWRON_FALL_INT;
priv->init_reg = rk817_init_reg;
priv->init_reg_num = ARRAY_SIZE(rk817_init_reg);
priv->irq_reg = rk817_irq_reg;
priv->irq_reg_num = ARRAY_SIZE(rk817_irq_reg);
break;
default:
return -EINVAL;
}
/* mask and clear intertup */
for (i = 0; i < priv->init_reg_num; i++) {
ret = pmic_reg_write(dev->parent,
priv->init_reg[i].reg,
priv->init_reg[i].val);
if (ret < 0) {
printf("%s: i2c write reg 0x%x failed, ret=%d\n",
__func__, priv->init_reg[i].reg, ret);
return ret;
}
debug("%s: reg[%x] = 0x%x\n", __func__, priv->init_reg[i].reg,
pmic_reg_read(dev->parent, priv->init_reg[i].reg));
}
return pwrkey_interrupt_init(dev);
}
U_BOOT_DRIVER(rk8xx_pwrkey) = {
.name = "rk8xx_pwrkey",
.id = UCLASS_KEY,
.ops = &key_ops,
.probe = rk8xx_pwrkey_probe,
.platdata_auto_alloc_size = sizeof(struct input_key),
.priv_auto_alloc_size = sizeof(struct rk8xx_key_priv),
};