summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Chang <georgekgchang@google.com>2021-04-23 19:20:38 +0800
committerGeorge Chang <georgekgchang@google.com>2021-04-26 20:21:56 +0800
commit97017f50c4e9dcdb89eeb7910e3eac64e0555393 (patch)
tree30d4804e6347d63c2e5bd8d426d7adc750f78897
parent992a91de71f29b480cfdcbe2f4986f18e56ffbc0 (diff)
downloadnfc-97017f50c4e9dcdb89eeb7910e3eac64e0555393.tar.gz
Add clock control ability in IOCTL
Turn on the clock at open and manage the clock on/off later by IOCTL. NFC HAL would switch on/off clock when it requires the clock signal. The NFC chip can't wait for clock delay more than 5 ms when requesting then clock, but the clock signal enabled by the clk_req handler might be delayed for more than 80 ms after clk_req goes high. Bug: 183693317 Test: on/off clock and get reg value via ioctl Signed-off-by: George Chang <georgekgchang@google.com> Change-Id: Ia51b269f0a521f3af6e0a0814531f0c35e152b37
-rw-r--r--st21nfc.c63
-rw-r--r--st21nfc.h3
2 files changed, 50 insertions, 16 deletions
diff --git a/st21nfc.c b/st21nfc.c
index d97665c..495f571 100644
--- a/st21nfc.c
+++ b/st21nfc.c
@@ -37,8 +37,9 @@
#define IDLE_CHARACTER 0x7e
#define ST21NFC_POWER_STATE_MAX 3
#define WAKEUP_SRC_TIMEOUT (2000)
+#define EXYNOS_CLK_MASK 0x01
-#define DRIVER_VERSION "2.0.16"
+#define DRIVER_VERSION "2.0.17"
#define PROP_PWR_MON_RW_ON_NTF nci_opcode_pack(NCI_GID_PROPRIETARY, 5)
#define PROP_PWR_MON_RW_OFF_NTF nci_opcode_pack(NCI_GID_PROPRIETARY, 6)
@@ -182,6 +183,20 @@ static int st21nfc_clock_deselect(struct st21nfc_device *st21nfc_dev)
return 0;
}
+static void st21nfc_exynos_clk_control(struct st21nfc_device *st21nfc_dev,
+ bool enable)
+{
+ if (st21nfc_dev->clk_pad) {
+ if (enable) {
+ exynos_pmu_update(st21nfc_dev->clk_pad, EXYNOS_CLK_MASK,
+ 1);
+ } else {
+ exynos_pmu_update(st21nfc_dev->clk_pad, EXYNOS_CLK_MASK,
+ 0);
+ }
+ }
+}
+
static irqreturn_t st21nfc_clkreq_irq_handler(int irq, void *dev_id)
{
struct st21nfc_device *st21nfc_dev = dev_id;
@@ -189,11 +204,10 @@ static irqreturn_t st21nfc_clkreq_irq_handler(int irq, void *dev_id)
if (st21nfc_dev->pinctrl_en) {
if (value)
- exynos_pmu_update(st21nfc_dev->clk_pad, 1, 1);
+ st21nfc_exynos_clk_control(st21nfc_dev, true);
else
- exynos_pmu_update(st21nfc_dev->clk_pad, 1, 0);
+ st21nfc_exynos_clk_control(st21nfc_dev, false);
}
-
return IRQ_HANDLED;
}
@@ -552,10 +566,11 @@ static int st21nfc_dev_open(struct inode *inode, struct file *filp)
if (st21nfc_dev->device_open) {
ret = -EBUSY;
- dev_err(&st21nfc_dev->client->dev,
- "%s : device already opened ret= %d\n", __func__, ret);
} else {
st21nfc_dev->device_open = true;
+ if (st21nfc_dev->clk_pad) {
+ st21nfc_exynos_clk_control(st21nfc_dev, true);
+ }
}
return ret;
}
@@ -568,6 +583,9 @@ static int st21nfc_release(struct inode *inode, struct file *file)
st21nfc_device);
st21nfc_dev->device_open = false;
+ if (st21nfc_dev->clk_pad) {
+ st21nfc_exynos_clk_control(st21nfc_dev, false);
+ }
return 0;
}
@@ -672,6 +690,20 @@ static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd,
ret = -ENODEV;
}
break;
+ case ST21NFC_CLK_ENABLE:
+ st21nfc_exynos_clk_control(st21nfc_dev, true);
+ break;
+ case ST21NFC_CLK_DISABLE:
+ st21nfc_exynos_clk_control(st21nfc_dev, false);
+ break;
+ case ST21NFC_CLK_STATE:
+ if (st21nfc_dev->clk_pad == 0 ||
+ exynos_pmu_read(st21nfc_dev->clk_pad, &ret) < 0) {
+ ret = -ENODEV;
+ } else {
+ ret &= EXYNOS_CLK_MASK;
+ }
+ break;
default:
dev_err(&st21nfc_dev->client->dev, "%s bad ioctl %u\n",
__func__, cmd);
@@ -1002,16 +1034,15 @@ static int st21nfc_probe(struct i2c_client *client,
}
}
- /* Set clk_run when clock pinctrl already enabled */
- if (st21nfc_dev->pinctrl_en != 0) {
- if (device_property_read_u32(dev,
- "pmu_clk_pad",
- &st21nfc_dev->clk_pad)) {
- dev_err(dev,
- "%s : PMU_CLKOUT_PAD offset is unset\n",
- __func__);
- st21nfc_dev->pinctrl_en = 0;
- }
+ /* Get clk_pad value*/
+ if (device_property_read_u32(dev,
+ "pmu_clk_pad",
+ &st21nfc_dev->clk_pad)) {
+ dev_err(dev,
+ "%s : PMU_CLKOUT_PAD offset is unset\n",
+ __func__);
+ st21nfc_dev->clk_pad = 0;
+ st21nfc_dev->pinctrl_en = 0;
}
ret = st21nfc_clock_select(st21nfc_dev);
diff --git a/st21nfc.h b/st21nfc.h
index 6202ff5..36ca1e7 100644
--- a/st21nfc.h
+++ b/st21nfc.h
@@ -21,5 +21,8 @@
#define ST21NFC_SET_POLARITY_HIGH _IOR(ST21NFC_MAGIC, 0x05, unsigned int)
#define ST21NFC_GET_POLARITY _IOR(ST21NFC_MAGIC, 0x07, unsigned int)
#define ST21NFC_RECOVERY _IOR(ST21NFC_MAGIC, 0x08, unsigned int)
+#define ST21NFC_CLK_ENABLE _IOR(ST21NFC_MAGIC, 0x11, unsigned int)
+#define ST21NFC_CLK_DISABLE _IOR(ST21NFC_MAGIC, 0x12, unsigned int)
+#define ST21NFC_CLK_STATE _IOR(ST21NFC_MAGIC, 0x13, unsigned int)
#endif