// SPDX-License-Identifier: GPL-2.0-only /* * NFC Controller Driver * Copyright (C) 2020 ST Microelectronics S.A. * Copyright (C) 2010 Stollmann E+V GmbH * Copyright (C) 2010 Trusted Logic S.A. */ /* * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #define DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef LEGACY #include #include #include #include #include #else #include #include #include #endif #include #include #include "st21nfc.h" #include "st_uapi.h" #include #ifdef NFC_SECURE_PERIPHERAL_ENABLED /*secure library headers*/ #include "smcinvoke_object.h" #include "IClientEnv.h" //NFC ID for registration with secure libraries #define HW_STATE_UID 0x108 #define HW_OP_GET_STATE 1 #define HW_NFC_UID 0x506 #define FEATURE_NOT_SUPPORTED 12 #define PERIPHERAL_NOT_FOUND 10 #endif // Uncomment this to check CLF response during probe // #define WITH_PING_DURING_PROBE // #define RECOVERY_SUPPORT_IN_PING #define MAX_BUFFER_SIZE 260 #define HEADER_LENGTH 3 #define IDLE_CHARACTER 0x7e #define ST21NFC_POWER_STATE_MAX 3 // wake up for the duration of a typical transaction #define WAKEUP_SRC_TIMEOUT (500) #define DRIVER_VERSION "2.2.0.19" #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) #define gpiod_set_value_t(x,y) if(!st21nfc_dev->secure_zone)\ gpiod_set_value(x,y) #define I2C_ID_NAME "st21nfc" #ifdef NFC_SECURE_PERIPHERAL_ENABLED static bool init_flag; #endif static bool enable_debug_log; /*The enum is used to index a pw_states array, the values matter here*/ enum st21nfc_power_state { ST21NFC_IDLE = 0, ST21NFC_ACTIVE = 1, ST21NFC_ACTIVE_RW = 2 }; static const char *const st21nfc_power_state_name[] = { "IDLE", "ACTIVE", "ACTIVE_RW" }; enum st21nfc_read_state { ST21NFC_HEADER, ST21NFC_PAYLOAD }; struct nfc_sub_power_stats { uint64_t count; uint64_t duration; uint64_t last_entry; uint64_t last_exit; }; struct nfc_sub_power_stats_error { /* error transition header --> payload state machine */ uint64_t header_payload; /* error transition from an active state when not in idle state */ uint64_t active_not_idle; /* error transition from idle state to idle state */ uint64_t idle_to_idle; /* warning transition from active_rw state to idle state */ uint64_t active_rw_to_idle; /* error transition from active state to active state */ uint64_t active_to_active; /* error transition from idle state to active state with notification */ uint64_t idle_to_active_ntf; /* error transition from active_rw state to active_rw state */ uint64_t act_rw_to_act_rw; /* error transition from idle state to */ /* active_rw state with notification */ uint64_t idle_to_active_rw_ntf; }; /* * The member 'polarity_mode' defines * how the wakeup pin is configured and handled. * it can take the following values : * IRQF_TRIGGER_RISING * IRQF_TRIGGER_HIGH */ struct st21nfc_device { wait_queue_head_t read_wq; struct mutex read_mutex; struct mutex pidle_mutex; struct mutex irq_dir_mutex; struct i2c_client *client; struct miscdevice st21nfc_device; uint8_t buffer[MAX_BUFFER_SIZE]; bool irq_enabled; bool irq_wake_up; struct wakeup_source * irq_wakeup_source; bool irq_is_attached; bool device_open; /* Is device open? */ spinlock_t irq_enabled_lock; enum st21nfc_power_state pw_current; enum st21nfc_read_state r_state_current; int irq_pw_stats_idle; int p_idle_last; struct nfc_sub_power_stats pw_states[ST21NFC_POWER_STATE_MAX]; struct nfc_sub_power_stats_error pw_states_err; struct workqueue_struct *st_p_wq; struct work_struct st_p_work; /*Power state shadow copies for reading*/ enum st21nfc_power_state c_pw_current; struct nfc_sub_power_stats c_pw_states[ST21NFC_POWER_STATE_MAX]; struct nfc_sub_power_stats_error c_pw_states_err; /* CLK control */ bool clk_run; struct clk *s_clk; uint8_t pinctrl_en; /* GPIO for NFCC IRQ pin (input) */ struct gpio_desc *gpiod_irq; /* GPIO for NFCC Reset pin (output) */ struct gpio_desc *gpiod_reset; /* GPIO for NFCC CLK_REQ pin (input) */ struct gpio_desc *gpiod_clkreq; /* GPIO for NFCC CLF_MONITOR_PWR (input) */ struct gpio_desc *gpiod_pidle; bool pidle_active_low; /* irq_gpio polarity to be used */ unsigned int polarity_mode; /*secure zone state*/ bool secure_zone; }; #if 0 /* * Routine to enable clock. * this routine can be extended to select from multiple * sources based on clk_src_name. */ static int st21nfc_clock_select(struct st21nfc_device *st21nfc_dev) { int ret = 0; st21nfc_dev->s_clk = clk_get(&st21nfc_dev->client->dev, "nfc_ref_clk"); /* if NULL we assume external crystal and dont fail */ if (IS_ERR_OR_NULL(st21nfc_dev->s_clk)) return 0; if (st21nfc_dev->clk_run == false) { ret = clk_prepare_enable(st21nfc_dev->s_clk); if (ret) goto err_clk; st21nfc_dev->clk_run = true; } return ret; err_clk: return -EINVAL; } #endif /* * Routine to disable clocks */ static int st21nfc_clock_deselect(struct st21nfc_device *st21nfc_dev) { /* if NULL we assume external crystal and dont fail */ if (IS_ERR_OR_NULL(st21nfc_dev->s_clk)) return 0; if (st21nfc_dev->clk_run == true) { clk_disable_unprepare(st21nfc_dev->s_clk); st21nfc_dev->clk_run = false; } return 0; } static void st21nfc_disable_irq(struct st21nfc_device *st21nfc_dev) { unsigned long flags; spin_lock_irqsave(&st21nfc_dev->irq_enabled_lock, flags); if (st21nfc_dev->irq_enabled) { disable_irq_nosync(st21nfc_dev->client->irq); st21nfc_dev->irq_enabled = false; } spin_unlock_irqrestore(&st21nfc_dev->irq_enabled_lock, flags); } static void st21nfc_enable_irq(struct st21nfc_device *st21nfc_dev) { unsigned long flags; spin_lock_irqsave(&st21nfc_dev->irq_enabled_lock, flags); if (!st21nfc_dev->irq_enabled) { st21nfc_dev->irq_enabled = true; enable_irq(st21nfc_dev->client->irq); } spin_unlock_irqrestore(&st21nfc_dev->irq_enabled_lock, flags); } static irqreturn_t st21nfc_dev_irq_handler(int irq, void *dev_id) { struct st21nfc_device *st21nfc_dev = dev_id; if (st21nfc_dev->irq_wakeup_source != NULL) __pm_wakeup_event(st21nfc_dev->irq_wakeup_source, WAKEUP_SRC_TIMEOUT); st21nfc_disable_irq(st21nfc_dev); /* Wake up waiting readers */ wake_up(&st21nfc_dev->read_wq); return IRQ_HANDLED; } static int st21nfc_loc_set_polaritymode(struct st21nfc_device *st21nfc_dev, int mode) { struct i2c_client *client = st21nfc_dev->client; struct device *dev = &client->dev; unsigned int irq_type; int ret; if (enable_debug_log) pr_info("%s:%d mode %d", __FILE__, __LINE__, mode); st21nfc_dev->polarity_mode = mode; /* setup irq_flags */ switch (mode) { case IRQF_TRIGGER_RISING: irq_type = IRQ_TYPE_EDGE_RISING; break; case IRQF_TRIGGER_HIGH: irq_type = IRQ_TYPE_LEVEL_HIGH; break; default: irq_type = IRQ_TYPE_EDGE_RISING; break; } if (st21nfc_dev->irq_is_attached) { devm_free_irq(dev, client->irq, st21nfc_dev); st21nfc_dev->irq_is_attached = false; } ret = irq_set_irq_type(client->irq, irq_type); if (ret) { pr_err("%s : set_irq_type failed\n", __func__); return -ENODEV; } /* request irq. the irq is set whenever the chip has data available * for reading. it is cleared when all data has been read. */ if (enable_debug_log) pr_debug("%s : requesting IRQ %d\n", __func__, client->irq); st21nfc_dev->irq_enabled = true; ret = devm_request_irq(dev, client->irq, st21nfc_dev_irq_handler, st21nfc_dev->polarity_mode, client->name, st21nfc_dev); if (ret) { pr_err("%s : devm_request_irq failed\n", __func__); return -ENODEV; } st21nfc_dev->irq_is_attached = true; st21nfc_disable_irq(st21nfc_dev); if (enable_debug_log) pr_info("%s:%d ret %d", __FILE__, __LINE__, ret); return ret; } static void st21nfc_power_stats_switch(struct st21nfc_device *st21nfc_dev, uint64_t current_time_ms, enum st21nfc_power_state old_state, enum st21nfc_power_state new_state, bool is_ntf) { mutex_lock(&st21nfc_dev->pidle_mutex); if (new_state == old_state) { if ((st21nfc_dev->pw_states[ST21NFC_IDLE].last_entry != 0) || (old_state != ST21NFC_IDLE)) { pr_err("%s Error: Switched from %s to %s!: %llx, ntf=%d\n", __func__, st21nfc_power_state_name[old_state], st21nfc_power_state_name[new_state], current_time_ms, is_ntf); if (new_state == ST21NFC_IDLE) st21nfc_dev->pw_states_err.idle_to_idle++; else if (new_state == ST21NFC_ACTIVE) st21nfc_dev->pw_states_err.active_to_active++; else if (new_state == ST21NFC_ACTIVE_RW) st21nfc_dev->pw_states_err.act_rw_to_act_rw++; mutex_unlock(&st21nfc_dev->pidle_mutex); return; } } else if (!is_ntf && new_state == ST21NFC_ACTIVE && old_state != ST21NFC_IDLE) { st21nfc_dev->pw_states_err.active_not_idle++; } else if (!is_ntf && new_state == ST21NFC_IDLE && old_state == ST21NFC_ACTIVE_RW) { st21nfc_dev->pw_states_err.active_rw_to_idle++; } else if (is_ntf && new_state == ST21NFC_ACTIVE && old_state == ST21NFC_IDLE) { st21nfc_dev->pw_states_err.idle_to_active_ntf++; } else if (is_ntf && new_state == ST21NFC_ACTIVE_RW && old_state == ST21NFC_IDLE) { st21nfc_dev->pw_states_err.idle_to_active_rw_ntf++; } pr_debug("%s Switching from %s to %s: %llx, ntf=%d\n", __func__, st21nfc_power_state_name[old_state], st21nfc_power_state_name[new_state], current_time_ms, is_ntf); st21nfc_dev->pw_states[old_state].last_exit = current_time_ms; st21nfc_dev->pw_states[old_state].duration += st21nfc_dev->pw_states[old_state].last_exit - st21nfc_dev->pw_states[old_state].last_entry; st21nfc_dev->pw_states[new_state].count++; st21nfc_dev->pw_current = new_state; st21nfc_dev->pw_states[new_state].last_entry = current_time_ms; mutex_unlock(&st21nfc_dev->pidle_mutex); } static void st21nfc_power_stats_idle_signal(struct st21nfc_device *st21nfc_dev) { uint64_t current_time_ms = ktime_to_ms(ktime_get_boottime()); int value = gpiod_get_value(st21nfc_dev->gpiod_pidle); if (st21nfc_dev->pidle_active_low) value = !value; if (value != 0) { st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, st21nfc_dev->pw_current, ST21NFC_ACTIVE, false); } else { st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, st21nfc_dev->pw_current, ST21NFC_IDLE, false); } } static void st21nfc_pstate_wq(struct work_struct *work) { struct st21nfc_device *st21nfc_dev = container_of(work, struct st21nfc_device, st_p_work); st21nfc_power_stats_idle_signal(st21nfc_dev); } static irqreturn_t st21nfc_dev_power_stats_handler(int irq, void *dev_id) { struct st21nfc_device *st21nfc_dev = dev_id; queue_work(st21nfc_dev->st_p_wq, &(st21nfc_dev->st_p_work)); return IRQ_HANDLED; } #ifdef ST54J_PWRSTATS static void st21nfc_power_stats_filter(struct st21nfc_device *st21nfc_dev, char *buf, size_t count) { uint64_t current_time_ms = ktime_to_ms(ktime_get_boottime()); __u16 ntf_opcode = nci_opcode(buf); if (IS_ERR(st21nfc_dev->gpiod_pidle)) return; /* In order to avoid counting active state on PAYLOAD where it would * match a possible header, power states are filtered only on NCI * headers. */ if (st21nfc_dev->r_state_current != ST21NFC_HEADER) return; if (count != HEADER_LENGTH) { pr_err("%s Warning: expect previous one was idle data\n"); st21nfc_dev->pw_states_err.header_payload++; return; } if (nci_mt(buf) != NCI_MT_NTF_PKT && nci_opcode_gid(ntf_opcode) != NCI_GID_PROPRIETARY) return; switch (ntf_opcode) { case PROP_PWR_MON_RW_OFF_NTF: st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, st21nfc_dev->pw_current, ST21NFC_ACTIVE, true); break; case PROP_PWR_MON_RW_ON_NTF: st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, st21nfc_dev->pw_current, ST21NFC_ACTIVE_RW, true); break; default: return; } } #endif static ssize_t st21nfc_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) { struct st21nfc_device *st21nfc_dev = container_of( filp->private_data, struct st21nfc_device, st21nfc_device); int ret; #ifdef ST54J_PWRSTATS int idle = 0; #endif // ST54J_PWRSTATS if (count == 0) return 0; if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; if (enable_debug_log) pr_debug("%s : reading %zu bytes.\n", __func__, count); if (gpiod_get_value(st21nfc_dev->gpiod_irq) == 0) { pr_info("%s : read called but no IRQ.\n", __func__); memset(st21nfc_dev->buffer, 0x7E, count); if (copy_to_user(buf, st21nfc_dev->buffer, count)) { pr_warn("%s : failed to copy to user space\n", __func__); return -EFAULT; } return count; } mutex_lock(&st21nfc_dev->read_mutex); /* Read data */ ret = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer, count); #ifdef ST54J_PWRSTATS if (ret < 0) { pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); mutex_unlock(&st21nfc_dev->read_mutex); return ret; } if (st21nfc_dev->r_state_current == ST21NFC_HEADER) { /* Counting idle index */ for (idle = 0; idle < ret && st21nfc_dev->buffer[idle] == IDLE_CHARACTER; idle++) ; if (idle > 0 && idle < HEADER_LENGTH) { memmove(st21nfc_dev->buffer, st21nfc_dev->buffer + idle, ret - idle); ret = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer + ret - idle, idle); if (ret < 0) { pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); mutex_unlock(&st21nfc_dev->read_mutex); return ret; } ret = count; } } #endif // ST54J_PWRSTATS mutex_unlock(&st21nfc_dev->read_mutex); if (ret < 0) { pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); return ret; } if (ret > count) { pr_err("%s: received too many bytes from i2c (%d)\n", __func__, ret); return -EIO; } #ifdef ST54J_PWRSTATS if (idle < HEADER_LENGTH) { st21nfc_power_stats_filter(st21nfc_dev, st21nfc_dev->buffer, ret); /* change state only if a payload is detected, i.e. size > 0*/ if ((st21nfc_dev->r_state_current == ST21NFC_HEADER) && (st21nfc_dev->buffer[2] > 0)) { st21nfc_dev->r_state_current = ST21NFC_PAYLOAD; if (enable_debug_log) pr_debug("%s : new state = ST21NFC_PAYLOAD\n", __func__); } else { st21nfc_dev->r_state_current = ST21NFC_HEADER; if (enable_debug_log) pr_debug("%s : new state = ST21NFC_HEADER\n", __func__); } } #endif // ST54J_PWRSTATS if (copy_to_user(buf, st21nfc_dev->buffer, ret)) { pr_warn("%s : failed to copy to user space\n", __func__); return -EFAULT; } return ret; } static ssize_t st21nfc_dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { struct st21nfc_device *st21nfc_dev = container_of( filp->private_data, struct st21nfc_device, st21nfc_device); char *tmp = NULL; int ret = count; if (enable_debug_log) { //pr_debug("%s: st21nfc_dev ptr %p\n", __func__, st21nfc_dev); pr_debug("%s : writing %zu bytes.\n", __func__, count); } if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; tmp = memdup_user(buf, count); if (IS_ERR_OR_NULL(tmp)) { pr_err("%s : memdup_user failed\n", __func__); return -EFAULT; } /* Write data */ ret = i2c_master_send(st21nfc_dev->client, tmp, count); if (ret != count) { pr_err("%s : i2c_master_send returned %d\n", __func__, ret); ret = -EIO; } kfree(tmp); return ret; } static int st21nfc_dev_open(struct inode *inode, struct file *filp) { int ret = 0; struct st21nfc_device *st21nfc_dev = container_of( filp->private_data, struct st21nfc_device, st21nfc_device); if (enable_debug_log) pr_info("%s:%d dev_open", __FILE__, __LINE__); if (st21nfc_dev->device_open) { ret = -EBUSY; pr_err("%s : device already opened ret= %d\n", __func__, ret); } else { st21nfc_dev->device_open = true; } return ret; } static int st21nfc_release(struct inode *inode, struct file *file) { struct st21nfc_device *st21nfc_dev = container_of( file->private_data, struct st21nfc_device, st21nfc_device); if (st21nfc_dev->irq_is_attached) { st21nfc_disable_irq(st21nfc_dev); devm_free_irq(&st21nfc_dev->client->dev, st21nfc_dev->client->irq, st21nfc_dev); st21nfc_dev->irq_is_attached = false; } st21nfc_dev->device_open = false; if (enable_debug_log) pr_debug("%s : device_open = false\n", __func__); return 0; } static void (*st21nfc_st54spi_cb)(int, void *); static void *st21nfc_st54spi_data; void st21nfc_register_st54spi_cb(void (*cb)(int, void *), void *data) { if (enable_debug_log) pr_info("%s\n", __func__); st21nfc_st54spi_cb = cb; st21nfc_st54spi_data = data; } void st21nfc_unregister_st54spi_cb(void) { if (enable_debug_log) pr_info("%s\n", __func__); st21nfc_st54spi_cb = NULL; st21nfc_st54spi_data = NULL; } #ifdef NFC_SECURE_PERIPHERAL_ENABLED /** * nfc_dynamic_protection_ioctl() - dynamic protection control * @nfc_dev: nfc device data structure * @sec_zone_trans: mode that we want to move to * If sec_zone_trans = 1; transition from non-secure zone to secure zone * If sec_zone_trans = 0; transition from secure zone to non - secure zone * * nfc periheral dynamic protection control. Depending on the sec_zone_trans value, device moves to * secure zone and non-secure zone * * Return: -ENOIOCTLCMD if sec_zone_trans val is not supported, 0 if Success(or no issue) * and error ret code otherwise */ int nfc_dynamic_protection_ioctl(struct st21nfc_device *st21nfc_dev, unsigned long sec_zone_trans) { int ret = 0; struct i2c_client *client = st21nfc_dev->client; struct device *dev = &client->dev; if(sec_zone_trans == 1) { pr_debug("%s: value %d\n", __func__, gpiod_get_value(st21nfc_dev->gpiod_reset)); gpiod_set_value(st21nfc_dev->gpiod_reset, 0); st21nfc_dev->secure_zone = true; pr_info("Driver Secure flag set successful\n"); } else if(sec_zone_trans == 0) { st21nfc_dev->secure_zone = false; if(init_flag) { /*Initialize once,only during the first non-secure entry*/ st21nfc_dev->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { pr_warn("%s : Unable to request reset-gpios\n", __func__); ret = -ENODEV; } else init_flag = false; } else { if (!gpiod_get_value(st21nfc_dev->gpiod_reset)) gpiod_set_value(st21nfc_dev->gpiod_reset, 1); } pr_info("Driver Secure flag clear successful\n"); } else { pr_info("INVALID ARG\n"); ret = -ENOIOCTLCMD; } return ret; } /** * nfc_hw_secure_check() - Checks the NFC secure zone status * * Queries the TZ secure libraries if NFC is in secure zone statue or not. * * Return: 0 if FEATURE_NOT_SUPPORTED/PERIPHERAL_NOT_FOUND/state is 2 and * return 1(non-secure) otherwise */ bool nfc_hw_secure_check(void) { struct Object client_env; struct Object app_object; u32 wifi_uid = HW_NFC_UID; union ObjectArg obj_arg[2] = {{{0, 0}}}; int ret; bool retstat = 1; u8 state = 0; /* get rootObj */ ret = get_client_env_object(&client_env); if (ret) { pr_err("Failed to get client_env_object, ret: %d\n", ret); return 1; } ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object); if (ret) { pr_debug("Failed to get app_object, ret: %d\n", ret); if (ret == FEATURE_NOT_SUPPORTED) { retstat = 0; /* Do not Assert */ pr_debug("Secure HW feature not supported\n"); } goto exit_release_clientenv; } obj_arg[0].b = (struct ObjectBuf) {&wifi_uid, sizeof(u32)}; obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)}; ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg, ObjectCounts_pack(1, 1, 0, 0)); pr_info("SMC invoke ret: %d state: %d\n", ret, state); if (ret) { if (ret == PERIPHERAL_NOT_FOUND) { retstat = 0; /* Do not Assert */ pr_debug("Secure HW mode is not updated. Peripheral not found\n"); } goto exit_release_app_obj; } if (state == 1) { /*Secure Zone*/ retstat = 1; } else { /*Non-Secure Zone*/ retstat = 0; } exit_release_app_obj: Object_release(app_object); exit_release_clientenv: Object_release(client_env); return retstat; } #endif static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct st21nfc_device *st21nfc_dev = container_of( filp->private_data, struct st21nfc_device, st21nfc_device); int ret = 0; u32 tmp; /* Check type and command number */ if (_IOC_TYPE(cmd) != ST21NFC_MAGIC) return -ENOTTY; /* Check access direction once here; don't repeat below. * IOC_DIR is from the user perspective, while access_ok is * from the kernel perspective; so they look reversed. */ if (_IOC_DIR(cmd) & _IOC_READ) ret = !ACCESS_OK(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); if (ret == 0 && _IOC_DIR(cmd) & _IOC_WRITE) ret = !ACCESS_OK(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (ret) return -EFAULT; #ifdef NFC_SECURE_PERIPHERAL_ENABLED if(st21nfc_dev->secure_zone) { if(cmd!=NFC_SECURE_ZONE) { pr_debug("Func nfc_dev_ioctl failed\n"); return -1; } } #endif switch (cmd) { case ST21NFC_SET_POLARITY_RISING: case ST21NFC_LEGACY_SET_POLARITY_RISING: pr_info(" ### ST21NFC_SET_POLARITY_RISING ###\n"); st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_RISING); break; case ST21NFC_SET_POLARITY_HIGH: case ST21NFC_LEGACY_SET_POLARITY_HIGH: pr_info(" ### ST21NFC_SET_POLARITY_HIGH ###\n"); #if 0 ret = st21nfc_clock_select(st21nfc_dev); if (ret < 0) pr_err("%s : st21nfc_clock_select failed\n", __func__); #endif st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_HIGH); break; case ST21NFC_PULSE_RESET: case ST21NFC_LEGACY_PULSE_RESET: pr_info("%s Double Pulse Request\n", __func__); if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { if (st21nfc_st54spi_cb != 0) (*st21nfc_st54spi_cb)(ST54SPI_CB_RESET_START, st21nfc_st54spi_data); /* pulse low for 20 millisecs */ gpiod_set_value_t(st21nfc_dev->gpiod_reset, 0); msleep(20); gpiod_set_value_t(st21nfc_dev->gpiod_reset, 1); usleep_range(10000, 11000); /* pulse low for 20 millisecs */ gpiod_set_value_t(st21nfc_dev->gpiod_reset, 0); msleep(20); gpiod_set_value_t(st21nfc_dev->gpiod_reset, 1); pr_info("%s done Double Pulse Request\n", __func__); if (st21nfc_st54spi_cb != 0) (*st21nfc_st54spi_cb)(ST54SPI_CB_RESET_END, st21nfc_st54spi_data); } st21nfc_dev->r_state_current = ST21NFC_HEADER; break; case ST21NFC_GET_WAKEUP: case ST21NFC_LEGACY_GET_WAKEUP: /* deliver state of Wake_up_pin as return value of ioctl */ ret = gpiod_get_value(st21nfc_dev->gpiod_irq); /* * Warning: depending on gpiod_get_value implementation, * it can returns a value different than 1 in case of high level */ if (ret != 0) ret = 1; if (enable_debug_log) pr_debug("%s get gpio result %d\n", __func__, ret); break; case ST21NFC_GET_POLARITY: case ST21NFC_LEGACY_GET_POLARITY: ret = st21nfc_dev->polarity_mode; if (enable_debug_log) pr_debug("%s get polarity %d\n", __func__, ret); break; case ST21NFC_RECOVERY: case ST21NFC_LEGACY_RECOVERY: /* For ST21NFCD usage only */ pr_info("%s Recovery Request\n", __func__); mutex_lock(&st21nfc_dev->irq_dir_mutex); if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { if (st21nfc_dev->irq_is_attached) { devm_free_irq(&st21nfc_dev->client->dev, st21nfc_dev->client->irq, st21nfc_dev); st21nfc_dev->irq_is_attached = false; } /* pulse low for 20 millisecs */ gpiod_set_value_t(st21nfc_dev->gpiod_reset, 0); usleep_range(10000, 11000); /* During the reset, force IRQ OUT as */ /* DH output instead of input in normal usage */ ret = gpiod_direction_output(st21nfc_dev->gpiod_irq, 1); if (ret) { pr_err("%s : gpiod_direction_output failed\n", __func__); ret = -ENODEV; mutex_unlock(&st21nfc_dev->irq_dir_mutex); break; } gpiod_set_value(st21nfc_dev->gpiod_irq, 1); usleep_range(10000, 11000); gpiod_set_value_t(st21nfc_dev->gpiod_reset, 1); pr_info("%s done Pulse Request\n", __func__); } msleep(20); gpiod_set_value(st21nfc_dev->gpiod_irq, 0); msleep(20); gpiod_set_value(st21nfc_dev->gpiod_irq, 1); msleep(20); gpiod_set_value(st21nfc_dev->gpiod_irq, 0); msleep(20); pr_info("%s Recovery procedure finished\n", __func__); ret = gpiod_direction_input(st21nfc_dev->gpiod_irq); if (ret) { pr_err("%s : gpiod_direction_input failed\n", __func__); ret = -ENODEV; } st21nfc_dev->irq_enabled = true; ret = devm_request_irq(&st21nfc_dev->client->dev, st21nfc_dev->client->irq, st21nfc_dev_irq_handler, st21nfc_dev->polarity_mode, st21nfc_dev->client->name, st21nfc_dev); if (ret) { pr_err("%s : devm_request_irq failed\n", __func__); mutex_unlock(&st21nfc_dev->irq_dir_mutex); return -ENODEV; } st21nfc_dev->irq_is_attached = true; st21nfc_disable_irq(st21nfc_dev); mutex_unlock(&st21nfc_dev->irq_dir_mutex); break; case ST21NFC_USE_ESE: ret = __get_user(tmp, (u32 __user *)arg); if (ret == 0) { if (st21nfc_st54spi_cb != 0) (*st21nfc_st54spi_cb)( tmp ? ST54SPI_CB_ESE_USED : ST54SPI_CB_ESE_NOT_USED, st21nfc_st54spi_data); } if (enable_debug_log) pr_debug("%s use ESE %d : %d\n", __func__, ret, tmp); break; #if 0 case ST21NFC_CLK_DISABLE_UNPREPARE: ret = st21nfc_clock_deselect(st21nfc_dev); if (ret < 0) { pr_err("%s : st21nfc_clock_deselect failed\n", __func__); } if (st21nfc_dev->irq_wakeup_source) { wakeup_source_unregister(st21nfc_dev->irq_wakeup_source); st21nfc_dev->irq_wakeup_source = NULL; } break; #endif #ifdef NFC_SECURE_PERIPHERAL_ENABLED case NFC_SECURE_ZONE: ret = nfc_dynamic_protection_ioctl(st21nfc_dev, arg); break; #endif default: pr_err("%s bad ioctl %u\n", __func__, cmd); ret = -EINVAL; break; } return ret; } static unsigned int st21nfc_poll(struct file *file, poll_table *wait) { struct st21nfc_device *st21nfc_dev = container_of( file->private_data, struct st21nfc_device, st21nfc_device); unsigned int mask = 0; int pinlev = 0; /* wait for Wake_up_pin == high */ poll_wait(file, &st21nfc_dev->read_wq, wait); pinlev = gpiod_get_value(st21nfc_dev->gpiod_irq); mutex_lock(&st21nfc_dev->irq_dir_mutex); if (pinlev != 0) { if (enable_debug_log) pr_debug("%s return ready\n", __func__); mask = POLLIN | POLLRDNORM; /* signal data avail */ st21nfc_disable_irq(st21nfc_dev); } else { /* Wake_up_pin is low. Activate ISR */ if (enable_debug_log) pr_debug("%s enable irq\n", __func__); st21nfc_enable_irq(st21nfc_dev); } mutex_unlock(&st21nfc_dev->irq_dir_mutex); return mask; } #ifdef WITH_PING_DURING_PROBE /* Attempt a communication with the chip. Return 0 on success, < 0 on failure */ static int st21nfc_ping(struct st21nfc_device *st21nfc_dev) { int ret = -ENODEV; int loops = 4; if (st21nfc_dev->device_open) { ret = -EBUSY; pr_err("%s : device already opened ret= %d\n", __func__, ret); return ret; } /* Some I2C masters have lazy init, attempt a dummy read first to initialize the pull-ups if needed */ (void)i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer, 1); /* pulse low for 20 millisecs */ gpiod_set_value(st21nfc_dev->gpiod_reset, 0); msleep(20); gpiod_set_value(st21nfc_dev->gpiod_reset, 1); usleep_range(10000, 11000); /* pulse low for 20 millisecs */ gpiod_set_value(st21nfc_dev->gpiod_reset, 0); msleep(20); gpiod_set_value(st21nfc_dev->gpiod_reset, 1); pr_info("%s done Double Pulse Request\n", __func__); msleep(10); // Read all incoming messages while IRQ is high. while ((loops-- > 0) && gpiod_get_value(st21nfc_dev->gpiod_irq)) { int len; // Read next message. len = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer, 3); if (len != 3) { pr_warn("%s Could not read header: %d\n", __func__, len); /* retry read */ } else { if (st21nfc_dev->buffer[0] == IDLE_CHARACTER) { if (st21nfc_dev->buffer[1] == IDLE_CHARACTER) { if (st21nfc_dev->buffer[2] == IDLE_CHARACTER) { pr_warn("%s Read 7E7E7E... header, IRQ always high ? Stop\n", __func__); break; } else { st21nfc_dev->buffer[0] = st21nfc_dev->buffer[2]; len = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer + 1, 2); if (len != 2) { pr_warn("%s Could not read rest of header after 7E7E: %d\n", __func__, len); break; } len = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer + 3, st21nfc_dev->buffer[2]); if (len != (int)st21nfc_dev->buffer[2]) { pr_warn("%s Could not read payload: %d\n", __func__, len); break; } } } else { // 4bytes header, read length st21nfc_dev->buffer[0] = st21nfc_dev->buffer[1]; st21nfc_dev->buffer[1] = st21nfc_dev->buffer[2]; len = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer + 2, 1); if (len != 1) { pr_warn("%s Could not read payload length: %d\n", __func__, len); break; } len = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer + 3, st21nfc_dev->buffer[2]); if (len != (int)st21nfc_dev->buffer[2]) { pr_warn("%s Could not read payload: %d\n", __func__, len); break; } } } else { // we got 3 bytes header len = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer + 3, st21nfc_dev->buffer[2]); if (len != (int)st21nfc_dev->buffer[2]) { pr_warn("%s Could not read payload: %d\n", __func__, len); break; } } pr_info("%s Read message (%d bytes): %02x %02x %02x %02x ...\n", __func__, len + 3, st21nfc_dev->buffer[0], st21nfc_dev->buffer[1], st21nfc_dev->buffer[2], st21nfc_dev->buffer[3] ); if (st21nfc_dev->buffer[0] == 0x60 && st21nfc_dev->buffer[1] == 0x00) { ret = 0; } msleep(5); } } return ret; } #ifdef RECOVERY_SUPPORT_IN_PING static int st21nfc_recovery(struct st21nfc_device *st21nfc_dev) { int ret = 0; /* This sequence allows to recover some chips that have become mute for SW reason */ pr_info("%s Recovery Request\n", __func__); mutex_lock(&st21nfc_dev->irq_dir_mutex); if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { /* pulse low for 20 millisecs */ gpiod_set_value(st21nfc_dev->gpiod_reset, 0); usleep_range(10000, 11000); /* During the reset, force IRQ OUT as */ /* DH output instead of input in normal usage */ ret = gpiod_direction_output(st21nfc_dev->gpiod_irq, 1); if (ret) { pr_err("%s : gpiod_direction_output failed\n", __func__); ret = -ENODEV; mutex_unlock(&st21nfc_dev->irq_dir_mutex); return ret; } gpiod_set_value(st21nfc_dev->gpiod_irq, 1); usleep_range(10000, 11000); gpiod_set_value(st21nfc_dev->gpiod_reset, 1); pr_info("%s done Pulse Request\n", __func__); } msleep(20); gpiod_set_value(st21nfc_dev->gpiod_irq, 0); msleep(20); gpiod_set_value(st21nfc_dev->gpiod_irq, 1); msleep(20); gpiod_set_value(st21nfc_dev->gpiod_irq, 0); msleep(20); pr_info("%s Recovery procedure finished\n", __func__); ret = gpiod_direction_input(st21nfc_dev->gpiod_irq); if (ret) { pr_err("%s : gpiod_direction_input failed\n", __func__); ret = -ENODEV; } mutex_unlock(&st21nfc_dev->irq_dir_mutex); return ret; } #endif // RECOVERY_SUPPORT_IN_PING #endif // WITH_PING_DURING_PROBE static const struct file_operations st21nfc_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = st21nfc_dev_read, .write = st21nfc_dev_write, .open = st21nfc_dev_open, .poll = st21nfc_poll, .release = st21nfc_release, .unlocked_ioctl = st21nfc_dev_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = st21nfc_dev_ioctl #endif }; static ssize_t i2c_addr_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); if (client != NULL) return scnprintf(buf, PAGE_SIZE, "0x%.2x\n", client->addr); return -ENODEV; } /* i2c_addr_show() */ static ssize_t i2c_addr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct st21nfc_device *data = dev_get_drvdata(dev); long new_addr = 0; if (data != NULL && data->client != NULL) { if (!kstrtol(buf, 10, &new_addr)) { mutex_lock(&data->read_mutex); data->client->addr = new_addr; mutex_unlock(&data->read_mutex); return count; } return -EINVAL; } return 0; } /* i2c_addr_store() */ static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%s\n", DRIVER_VERSION); } /* version_show */ static uint64_t st21nfc_power_duration(struct st21nfc_device *data, enum st21nfc_power_state pstate, uint64_t current_time_ms) { return data->c_pw_current != pstate ? data->c_pw_states[pstate].duration : data->c_pw_states[pstate].duration + (current_time_ms - data->c_pw_states[pstate].last_entry); } static ssize_t power_stats_show(struct device *dev, struct device_attribute *attr, char *buf) { struct st21nfc_device *data = dev_get_drvdata(dev); uint64_t current_time_ms; uint64_t idle_duration; uint64_t active_ce_duration; uint64_t active_rw_duration; mutex_lock(&data->pidle_mutex); data->c_pw_current = data->pw_current; data->c_pw_states_err = data->pw_states_err; memcpy(data->c_pw_states, data->pw_states, ST21NFC_POWER_STATE_MAX * sizeof(struct nfc_sub_power_stats)); mutex_unlock(&data->pidle_mutex); current_time_ms = ktime_to_ms(ktime_get_boottime()); idle_duration = st21nfc_power_duration(data, ST21NFC_IDLE, current_time_ms); active_ce_duration = st21nfc_power_duration(data, ST21NFC_ACTIVE, current_time_ms); active_rw_duration = st21nfc_power_duration(data, ST21NFC_ACTIVE_RW, current_time_ms); return scnprintf( buf, PAGE_SIZE, "NFC subsystem\n" "Idle mode:\n" "\tCumulative count: 0x%llx\n" "\tCumulative duration msec: 0x%llx\n" "\tLast entry timestamp msec: 0x%llx\n" "\tLast exit timestamp msec: 0x%llx\n" "Active mode:\n" "\tCumulative count: 0x%llx\n" "\tCumulative duration msec: 0x%llx\n" "\tLast entry timestamp msec: 0x%llx\n" "\tLast exit timestamp msec: 0x%llx\n" "Active Reader/Writer mode:\n" "\tCumulative count: 0x%llx\n" "\tCumulative duration msec: 0x%llx\n" "\tLast entry timestamp msec: 0x%llx\n" "\tLast exit timestamp msec: 0x%llx\n" "\nError transition header --> payload state machine: 0x%llx\n" "Error transition from an Active state when not in Idle state: 0x%llx\n" "Error transition from Idle state to Idle state: 0x%llx\n" "Warning transition from Active Reader/Writer state to Idle state: 0x%llx\n" "Error transition from Active state to Active state: 0x%llx\n" "Error transition from Idle state to Active state with notification: 0x%llx\n" "Error transition from Active Reader/Writer state to Active Reader/Writer state: 0x%llx\n" "Error transition from Idle state to Active Reader/Writer state with notification: 0x%llx\n" "\nTotal uptime: 0x%llx Cumulative modes time: 0x%llx\n", data->c_pw_states[ST21NFC_IDLE].count, idle_duration, data->c_pw_states[ST21NFC_IDLE].last_entry, data->c_pw_states[ST21NFC_IDLE].last_exit, data->c_pw_states[ST21NFC_ACTIVE].count, active_ce_duration, data->c_pw_states[ST21NFC_ACTIVE].last_entry, data->c_pw_states[ST21NFC_ACTIVE].last_exit, data->c_pw_states[ST21NFC_ACTIVE_RW].count, active_rw_duration, data->c_pw_states[ST21NFC_ACTIVE_RW].last_entry, data->c_pw_states[ST21NFC_ACTIVE_RW].last_exit, data->c_pw_states_err.header_payload, data->c_pw_states_err.active_not_idle, data->c_pw_states_err.idle_to_idle, data->c_pw_states_err.active_rw_to_idle, data->c_pw_states_err.active_to_active, data->c_pw_states_err.idle_to_active_ntf, data->c_pw_states_err.act_rw_to_act_rw, data->c_pw_states_err.idle_to_active_rw_ntf, current_time_ms, idle_duration + active_ce_duration + active_rw_duration); } static DEVICE_ATTR_RW(i2c_addr); static DEVICE_ATTR_RO(version); static DEVICE_ATTR_RO(power_stats); static struct attribute *st21nfc_attrs[] = { &dev_attr_i2c_addr.attr, &dev_attr_version.attr, &dev_attr_power_stats.attr, NULL, }; static struct attribute_group st21nfc_attr_grp = { .attrs = st21nfc_attrs, }; // QCOM and MTK54 use standard GPIO definition static const struct acpi_gpio_params irq_gpios = { 0, 0, false }; static const struct acpi_gpio_params reset_gpios = { 1, 0, false }; static const struct acpi_gpio_params pidle_gpios = { 2, 0, false }; static const struct acpi_gpio_params clkreq_gpios = { 3, 0, false }; static const struct acpi_gpio_mapping acpi_st21nfc_gpios[] = { { "irq-gpios", &irq_gpios, 1 }, { "reset-gpios", &reset_gpios, 1 }, { "pidle-gpios", &pidle_gpios, 1 }, { "clkreq-gpios", &clkreq_gpios, 1 }, }; #if (KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE) static int st21nfc_probe(struct i2c_client *client) #else static int st21nfc_probe(struct i2c_client *client, const struct i2c_device_id *id) #endif { int ret; struct st21nfc_device *st21nfc_dev; struct device *dev = &client->dev; unsigned int clkreq_gpio = 0; pr_info("%s: enter\n",__func__); #ifdef RECOVERY_SUPPORT_IN_PING int t; #endif if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s : need I2C_FUNC_I2C\n", __func__); return -ENODEV; } st21nfc_dev = devm_kzalloc(dev, sizeof(*st21nfc_dev), GFP_KERNEL); if (st21nfc_dev == NULL) return -ENOMEM; /* store for later use */ st21nfc_dev->client = client; st21nfc_dev->r_state_current = ST21NFC_HEADER; // QCOM and MTK54 use standard GPIO definition ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_st21nfc_gpios); if (ret) pr_debug("Unable to add GPIO mapping table\n"); // QCOM and MTK54 use standard GPIO definition st21nfc_dev->gpiod_irq = devm_gpiod_get(dev, "irq", GPIOD_IN); if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_irq)) { pr_err("%s : Unable to request irq-gpios\n", __func__); return -ENODEV; } #ifdef NFC_SECURE_PERIPHERAL_ENABLED /*Check NFC Secure Zone status*/ if(!nfc_hw_secure_check()) { // QTI and MTK54 use standard GPIO definition st21nfc_dev->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { pr_warn("%s : Unable to request reset-gpios\n", __func__); return -ENODEV; } st21nfc_dev->secure_zone = false; init_flag = false; } else { st21nfc_dev->secure_zone = true; init_flag = true; } #else // QTI and MTK54 use standard GPIO definition st21nfc_dev->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { pr_warn("%s : Unable to request reset-gpios\n", __func__); return -ENODEV; } st21nfc_dev->secure_zone = false; #endif pr_info("%s:st21nfc_dev->secure_zone = %s", __func__, st21nfc_dev->secure_zone ? "true" : "false"); // QCOM and MTK54 use standard GPIO definition st21nfc_dev->gpiod_pidle = devm_gpiod_get(dev, "pidle", GPIOD_IN); if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { pr_warn("[OPTIONAL] %s: Unable to request pidle-gpio\n", __func__); ret = 0; } else { if (!device_property_read_bool(dev, "st,pidle_active_low")) { pr_info("%s:[OPTIONAL] pidle_active_low not set\n", __func__); st21nfc_dev->pidle_active_low = false; } else { pr_info("%s:[OPTIONAL] pidle_active_low set\n", __func__); st21nfc_dev->pidle_active_low = true; } /* Prepare a workqueue for st21nfc_dev_power_stats_handler */ st21nfc_dev->st_p_wq = create_workqueue("st_pstate_work"); if(!st21nfc_dev->st_p_wq) { devm_gpiod_put(dev,st21nfc_dev->gpiod_pidle); devm_gpiod_put(dev,st21nfc_dev->gpiod_reset); devm_gpiod_put(dev,st21nfc_dev->gpiod_irq); return -ENODEV; } mutex_init(&st21nfc_dev->pidle_mutex); INIT_WORK(&(st21nfc_dev->st_p_work), st21nfc_pstate_wq); /* Start the power stat in power mode idle */ st21nfc_dev->irq_pw_stats_idle = gpiod_to_irq(st21nfc_dev->gpiod_pidle); ret = irq_set_irq_type(st21nfc_dev->irq_pw_stats_idle, IRQ_TYPE_EDGE_BOTH); if (ret) { pr_err("%s : set_irq_type failed\n", __func__); goto err_pidle_workqueue; } /* This next call requests an interrupt line */ ret = devm_request_irq( dev, st21nfc_dev->irq_pw_stats_idle, (irq_handler_t)st21nfc_dev_power_stats_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, /* Interrupt on both edges */ "st21nfc_pw_stats_idle_handle", st21nfc_dev); if (ret) { pr_err("%s : devm_request_irq for power stats idle failed\n", __func__); goto err_pidle_workqueue; } } st21nfc_dev->gpiod_clkreq = devm_gpiod_get(dev, "clkreq", GPIOD_IN); if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_clkreq)) { st21nfc_dev->clk_run = false; } else { /* Read clkreq GPIO number from device tree*/ ret = of_property_read_u32_index(client->dev.of_node, "clkreq-gpios", 1, &clkreq_gpio); if (ret < 0) { pr_err("%s Failed to read clkreq gipo number, ret: %d\n", __func__, ret); return ret; } /* configure clkreq GPIO as wakeup capable */ ret = msm_gpio_mpm_wake_set(clkreq_gpio, true); if (ret < 0) { pr_err("%s Failed to setup clkreq gpio %d as wakeup capable, ret: %d\n", __func__, clkreq_gpio , ret); return ret; } else pr_info("%s clkreq gpio %d successfully setup for wakeup capable\n", __func__, clkreq_gpio); if (!device_property_read_bool(dev, "st,clk_pinctrl")) { pr_debug("%s:[OPTIONAL] clk_pinctrl not set\n", __func__); st21nfc_dev->pinctrl_en = 0; } else { pr_debug("%s:[OPTIONAL] clk_pinctrl set\n", __func__); st21nfc_dev->pinctrl_en = 1; } /* Set clk_run when clock pinctrl already enabled */ if (st21nfc_dev->pinctrl_en != 0) st21nfc_dev->clk_run = true; } client->irq = gpiod_to_irq(st21nfc_dev->gpiod_irq); /* I2C retry management: we want only 1 attempt at communication. As some busses need retry=1 and most need retry=0, we add optional DTS entry */ if (of_property_read_u32(dev->of_node, "i2c-retry", &client->adapter->retries)) { client->adapter->retries = 0; } else { pr_debug("%s : i2c-retry = %d\n", __func__, client->adapter->retries); } #ifdef WITH_PING_DURING_PROBE #ifdef RECOVERY_SUPPORT_IN_PING for(t = 0; t < 3; t++) { int rc; ret = st21nfc_ping(st21nfc_dev); if (ret == 0) break; pr_err("%s: Did not get CORE_RESET_NTF (%d), try recovery\n", __func__, ret); rc = st21nfc_recovery(st21nfc_dev); pr_info("%s: recovery done (#%d), result = %d, try ping again\n", __func__, t, rc); } // try the next ping only if last one failed if (ret != 0) { #endif // RECOVERY_SUPPORT_IN_PING if ((ret = st21nfc_ping(st21nfc_dev))) { pr_err("%s: Did not get CORE_RESET_NTF, hardware issue? (%d)\n", __func__, ret); goto err_pidle_workqueue; } #ifdef RECOVERY_SUPPORT_IN_PING } #endif // RECOVERY_SUPPORT_IN_PING #endif // WITH_PING_DURING_PROBE /* init mutex and queues */ init_waitqueue_head(&st21nfc_dev->read_wq); mutex_init(&st21nfc_dev->read_mutex); mutex_init(&st21nfc_dev->irq_dir_mutex); spin_lock_init(&st21nfc_dev->irq_enabled_lock); pr_debug( "%s : debug irq_gpio = %d, client-irq = %d, pidle_gpio = %d\n", __func__, IS_ERR_OR_NULL(st21nfc_dev->gpiod_irq) ? -1 : desc_to_gpio(st21nfc_dev->gpiod_irq), client->irq, IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle) ? -1 : desc_to_gpio(st21nfc_dev->gpiod_pidle)); st21nfc_dev->st21nfc_device.minor = MISC_DYNAMIC_MINOR; st21nfc_dev->st21nfc_device.name = "st21nfc"; st21nfc_dev->st21nfc_device.fops = &st21nfc_dev_fops; st21nfc_dev->st21nfc_device.parent = dev; i2c_set_clientdata(client, st21nfc_dev); ret = misc_register(&st21nfc_dev->st21nfc_device); if (ret) { pr_err("%s : misc_register failed\n", __func__); goto err_misc_register; } ret = sysfs_create_group(&dev->kobj, &st21nfc_attr_grp); if (ret) { pr_err("%s : sysfs_create_group failed\n", __func__); goto err_sysfs_create_group_failed; } st21nfc_dev->irq_wakeup_source = wakeup_source_register(NULL, "st21nfc"); st21nfc_dev->irq_wake_up = false; pr_info("%s: probing nfc i2c success\n",__func__); return 0; err_sysfs_create_group_failed: misc_deregister(&st21nfc_dev->st21nfc_device); err_misc_register: mutex_destroy(&st21nfc_dev->read_mutex); mutex_destroy(&st21nfc_dev->irq_dir_mutex); if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { sysfs_remove_file(&client->dev.kobj, &dev_attr_power_stats.attr); } err_pidle_workqueue: if (!IS_ERR(st21nfc_dev->gpiod_pidle)) { mutex_destroy(&st21nfc_dev->pidle_mutex); destroy_workqueue(st21nfc_dev->st_p_wq); devm_gpiod_put(dev,st21nfc_dev->gpiod_pidle); } if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { devm_gpiod_put(dev,st21nfc_dev->gpiod_reset); } if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_irq)) { devm_gpiod_put(dev,st21nfc_dev->gpiod_irq); } if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_clkreq)) { devm_gpiod_put(dev,st21nfc_dev->gpiod_clkreq); } return ret; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) static void st21nfc_remove(struct i2c_client *client) #else static int st21nfc_remove(struct i2c_client *client) #endif { struct st21nfc_device *st21nfc_dev = i2c_get_clientdata(client); st21nfc_clock_deselect(st21nfc_dev); misc_deregister(&st21nfc_dev->st21nfc_device); if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { sysfs_remove_file(&client->dev.kobj, &dev_attr_power_stats.attr); mutex_destroy(&st21nfc_dev->pidle_mutex); devm_gpiod_put(&client->dev,st21nfc_dev->gpiod_pidle); } sysfs_remove_group(&client->dev.kobj, &st21nfc_attr_grp); if (st21nfc_dev->irq_wakeup_source) { wakeup_source_unregister(st21nfc_dev->irq_wakeup_source); st21nfc_dev->irq_wakeup_source = NULL; } mutex_destroy(&st21nfc_dev->read_mutex); mutex_destroy(&st21nfc_dev->irq_dir_mutex); acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { devm_gpiod_put(&client->dev,st21nfc_dev->gpiod_reset); } if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_irq)) { devm_gpiod_put(&client->dev,st21nfc_dev->gpiod_irq); } if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_clkreq)) { devm_gpiod_put(&client->dev,st21nfc_dev->gpiod_clkreq); } #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) return 0; #endif } static int st21nfc_suspend(struct device *device) { struct i2c_client *client = to_i2c_client(device); struct st21nfc_device *st21nfc_dev = i2c_get_clientdata(client); if (st21nfc_dev->irq_enabled) { if (!enable_irq_wake(client->irq)) st21nfc_dev->irq_wake_up = true; } if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) st21nfc_dev->p_idle_last = gpiod_get_value(st21nfc_dev->gpiod_pidle); return 0; } static int st21nfc_resume(struct device *device) { struct i2c_client *client = to_i2c_client(device); struct st21nfc_device *st21nfc_dev = i2c_get_clientdata(client); int pidle; if (st21nfc_dev->irq_wake_up) { if (!disable_irq_wake(client->irq)) st21nfc_dev->irq_wake_up = false; } if (!IS_ERR(st21nfc_dev->gpiod_pidle)) { pidle = gpiod_get_value(st21nfc_dev->gpiod_pidle); if ((st21nfc_dev->p_idle_last != pidle) || (st21nfc_dev->pw_current == ST21NFC_IDLE && pidle != 0) || (st21nfc_dev->pw_current == ST21NFC_ACTIVE && pidle == 0)) queue_work(st21nfc_dev->st_p_wq, &(st21nfc_dev->st_p_work)); } return 0; } static const struct i2c_device_id st21nfc_id[] = { { "st21nfc", 0 }, {} }; static const struct of_device_id st21nfc_of_match[] = { { .compatible = "st,st21nfc", }, {} }; MODULE_DEVICE_TABLE(of, st21nfc_of_match); static const struct dev_pm_ops st21nfc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS( st21nfc_suspend, st21nfc_resume) }; #ifdef CONFIG_ACPI static const struct acpi_device_id st21nfc_acpi_match[] = { { "SMO2104" }, {} }; MODULE_DEVICE_TABLE(acpi, st21nfc_acpi_match); #endif // CONFIG_ACPI static struct i2c_driver st21nfc_driver = { .id_table = st21nfc_id, .probe = st21nfc_probe, .remove = st21nfc_remove, .driver = { .owner = THIS_MODULE, .name = I2C_ID_NAME, .of_match_table = st21nfc_of_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = &st21nfc_pm_ops, #ifdef CONFIG_ACPI .acpi_match_table = ACPI_PTR(st21nfc_acpi_match), #endif // CONFIG_ACPI }, }; #ifdef GKI_MODULE module_i2c_driver(st21nfc_driver); #else // GKI_MODULE /* module load/unload record keeping */ static int __init st21nfc_dev_init(void) { pr_info("Loading st21nfc driver %s\n", DRIVER_VERSION); return i2c_add_driver(&st21nfc_driver); } module_init(st21nfc_dev_init); static void __exit st21nfc_dev_exit(void) { pr_info("Unloading st21nfc driver\n"); i2c_del_driver(&st21nfc_driver); } module_exit(st21nfc_dev_exit); #endif // GKI_MODULE MODULE_AUTHOR("STMicroelectronics"); MODULE_DESCRIPTION("NFC ST21NFC driver"); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL");