Loading drivers/nfc/nfc-nci.c +276 −61 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ struct qca199x_platform_data { unsigned int dis_gpio; unsigned int ven_gpio; unsigned int reg; const char *clk_src; const char *clk_src_name; unsigned int clk_src_gpio; }; Loading @@ -45,14 +45,18 @@ static struct of_device_id msm_match_table[] = { MODULE_DEVICE_TABLE(of, msm_match_table); #define MAX_BUFFER_SIZE (780) #define PACKET_MAX_LENGTH (258) /* Read data */ #define PACKET_HEADER_SIZE_NCI (4) #define PACKET_TYPE_NCI (16) #define MAX_PACKET_SIZE (PACKET_HEADER_SIZE_NCI + 255) #define MAX_QCA_REG (116) /* will timeout in approx. 100ms as 10us steps */ #define NTF_TIMEOUT (10000) #define CORE_RESET_RSP_GID (0x60) #define CORE_RESET_OID (0x00) #define CORE_RST_NTF_LENGTH (0x02) static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len); static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr); struct qca199x_dev { wait_queue_head_t read_wq; Loading @@ -63,11 +67,23 @@ struct qca199x_dev { unsigned int dis_gpio; unsigned int ven_gpio; bool irq_enabled; bool sent_first_nci_write; spinlock_t irq_enabled_lock; unsigned int count_irq; enum nfcc_state state; unsigned int clk_src_gpio; const char *clk_src_name; struct clk *s_clk; bool clk_run; }; static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len); static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr); static int qca199x_clock_select(struct qca199x_dev *qca199x_dev); static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev); /* * To allow filtering of nfc logging from user. This is set via * IOCTL NFC_KERNEL_LOGGING_MODE. Loading Loading @@ -205,24 +221,34 @@ static ssize_t nfc_read(struct file *filp, char __user *buf, /* NORMAL NCI Behaviour */ /* Read the header */ ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH); /* We ignore all packets of length PAYLOAD_HEADER_LENGTH or less (i.e <=3). In this case return a total length of ZERO. So ALL PACKETS MUST HAVE A PAYLOAD. If ret < 0 then this is an error code. */ if (ret != PAYLOAD_HEADER_LENGTH) { if (ret < 0) total = ret; else total = 0; goto err; } length = len[PAYLOAD_HEADER_LENGTH - 1]; if (length == 0) total = 0; if (length == 0) { ret = 0; total = ret; goto err; } /** make sure full packet fits in the buffer **/ if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) { /* Read the packet */ ret = i2c_master_recv(qca199x_dev->client, tmp, (length + PAYLOAD_HEADER_LENGTH)); if (ret < 0) { total = 0; total = ret; if (ret < 0) goto err; } total = (length + PAYLOAD_HEADER_LENGTH); } if (total > 0) { if ((total > count) || copy_to_user(buf, tmp, total)) { Loading @@ -232,14 +258,57 @@ static ssize_t nfc_read(struct file *filp, char __user *buf, total = -EFAULT; } } mutex_unlock(&qca199x_dev->read_mutex); err: if (ret < 0) mutex_unlock(&qca199x_dev->read_mutex); done: return total; } /* Local routine to read from nfcc buffer. This is called to clear any pending receive messages in the nfcc's read buffer, which may be there following a POR. In this way, the upper layers (Device Transport) will associate the next rsp/ntf nci message with the next nci command to the nfcc. Otherwise, the DT may interpret a ntf from the nfcc as being from the nci core reset command when in fact it was already present in the nfcc read buffer following a POR. */ int nfcc_read_buff_svc(struct qca199x_dev *qca199x_dev) { unsigned char tmp[PACKET_MAX_LENGTH]; unsigned char len[PAYLOAD_HEADER_LENGTH]; int total, length, ret; total = 0; length = 0; mutex_lock(&qca199x_dev->read_mutex); memset(tmp, 0, sizeof(tmp)); memset(len, 0, sizeof(len)); /* Read the header */ ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH); if (ret < PAYLOAD_HEADER_LENGTH) { total = ret; goto leave; } length = len[PAYLOAD_HEADER_LENGTH - 1]; if (length == 0) { ret = PAYLOAD_HEADER_LENGTH; total = ret; goto leave; } /** make sure full packet fits in the buffer **/ if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= PACKET_MAX_LENGTH)) { /* Read the packet */ ret = i2c_master_recv(qca199x_dev->client, tmp, (length + PAYLOAD_HEADER_LENGTH)); total = ret; } leave: mutex_unlock(&qca199x_dev->read_mutex); return total; } static ssize_t nfc_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { Loading @@ -247,6 +316,7 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf, char tmp[MAX_BUFFER_SIZE]; int ret = 0; enum ehandler_mode dmode; int nfcc_buffer = 0; if (count > MAX_BUFFER_SIZE) { dev_err(&qca199x_dev->client->dev, "out of memory\n"); Loading @@ -257,6 +327,24 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf, "nfc-nci write: failed to copy from user space\n"); return -EFAULT; } /* A catch for when the DT is sending the initial NCI write following a hardware POR. In this case we should clear any pending messages in nfcc buffer and open the interrupt gate for new messages coming from the nfcc. */ if ((qca199x_dev->sent_first_nci_write == false) && (qca199x_dev->irq_enabled == false)) { /* check rsp/ntf from nfcc read-side buffer */ nfcc_buffer = nfcc_read_buff_svc(qca199x_dev); /* There has been an error while reading from nfcc */ if (nfcc_buffer < 0) { dev_err(&qca199x_dev->client->dev, "nfc-nci write: error while servicing nfcc read buffer\n"); } qca199x_dev->sent_first_nci_write = true; qca199x_enable_irq(qca199x_dev); } mutex_lock(&qca199x_dev->read_mutex); dmode = device_mode.handle_flavour; /* FTM-DIRECT-I2C RD/WR MODE */ Loading Loading @@ -378,6 +466,9 @@ int nfc_ioctl_power_states(struct file *filp, unsigned int cmd, struct qca199x_dev *qca199x_dev = filp->private_data; if (arg == 0) { r = qca199x_clock_select(qca199x_dev); if (r < 0) goto err_req; gpio_set_value(qca199x_dev->dis_gpio, 0); r = gpio_direction_output(qca199x_dev->dis_gpio, 1); if (r) { Loading @@ -389,6 +480,23 @@ int nfc_ioctl_power_states(struct file *filp, unsigned int cmd, gpio_set_value(qca199x_dev->dis_gpio, 0); msleep(20); } else if (arg == 1) { /* We are attempting a hardware reset so let us disable interrupts to avoid spurious notifications to upper layers. */ qca199x_disable_irq(qca199x_dev); /* Deselection of clock */ r = qca199x_clock_deselect(qca199x_dev); if (r < 0) goto err_req; /* Also, set flag for initial NCI write following resetas may wish to do some house keeping. Ensure no pending messages in NFCC buffers which may be wrongly construed as response to initial message */ qca199x_dev->sent_first_nci_write = false; gpio_set_value(qca199x_dev->dis_gpio, 0); r = gpio_direction_output(qca199x_dev->dis_gpio, 1); if (r) { Loading @@ -402,10 +510,12 @@ int nfc_ioctl_power_states(struct file *filp, unsigned int cmd, } else if (arg == 2) { mutex_lock(&qca199x_dev->read_mutex); r = nfcc_initialise(qca199x_dev->client, 0xE); /* Also reset first NCI write */ qca199x_dev->sent_first_nci_write = false; mutex_unlock(&qca199x_dev->read_mutex); if (r) { dev_err(&qca199x_dev->client->dev, "nfc-nci probe: request nfcc initialise failed\n"); "nfc_ioctl_power_states: request nfcc initialise failed\n"); goto err_req; } } else if (arg == 3) { Loading Loading @@ -536,8 +646,6 @@ invalid_wr: return raw_chip_version; } /* * Inside nfc_ioctl_kernel_logging * Loading Loading @@ -664,72 +772,202 @@ static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr) unsigned char raw_1P8_PAD_CFG_CLK_REQ[] = {0xA5, 0x1}; unsigned char raw_1P8_PAD_CFG_PWR_REQ[] = {0xA7, 0x1}; unsigned char buf = 0; bool core_reset_completed = false; unsigned char rsp[6]; int time_taken = 0; int ret = 0; client->addr = curr_addr; r = i2c_master_send(client, &buf, 1); if (r < 0) goto err_init; buf = 0; r = i2c_master_recv(client, &buf, 1); if (r < 0) goto err_init; if (0x10 != (0x10 & buf)) { RAW(s73, 0x02); r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73)); if (r < 0) goto err_init; usleep(1000); RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01); r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0], sizeof(raw_1p8_CONTROL_011)); if (r < 0) goto err_init; usleep(1000); RAW(1P8_CONTROL_010, (0x8)); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(10000); /* 10ms wait */ RAW(1P8_CONTROL_010, (0xC)); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(100); /* 100uS wait */ RAW(1P8_X0_0B0, (FREQ_SEL_19)); r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0)); if (r < 0) goto err_init; usleep(1000); /* PWR_EN = 1 */ RAW(1P8_CONTROL_010, (0xd)); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(20000); /* 20ms wait */ /* LS_EN = 1 */ RAW(1P8_CONTROL_010, 0xF); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(20000); /* 20ms wait */ /* Enable the PMIC clock */ RAW(1P8_PAD_CFG_CLK_REQ, (0x1)); r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0], sizeof(raw_1P8_PAD_CFG_CLK_REQ)); if (r < 0) goto err_init; usleep(1000); RAW(1P8_PAD_CFG_PWR_REQ, (0x1)); r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0], sizeof(raw_1P8_PAD_CFG_PWR_REQ)); if (r < 0) goto err_init; usleep(1000); RAW(slave2, 0x10); r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2)); if (r < 0) goto err_init; usleep(1000); RAW(slave1, NCI_I2C_SLAVE); r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1)); if (r < 0) goto err_init; usleep(1000); /* QCA199x NFCC CPU should now boot... */ r = i2c_master_recv(client, &raw_slave1_rd, 1); /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/ client->addr = NCI_I2C_SLAVE; /* Start with small delay and then we will poll until we get a core reset notification - This is time for chip & NFCC controller to come-up. */ usleep(1000); /* 1 ms */ do { ret = i2c_master_recv(client, rsp, 5); /* Found core reset notification */ if (((rsp[0] == CORE_RESET_RSP_GID) && (rsp[1] == CORE_RESET_OID) && (rsp[2] == CORE_RST_NTF_LENGTH)) || time_taken == NTF_TIMEOUT) { core_reset_completed = true; } usleep(10); /* 10us sleep before retry */ time_taken++; } while (!core_reset_completed); r = 0; } else { goto err_init; } return r; err_init: r = 1; dev_err(&client->dev, "nfc-nci nfcc_initialise: failed. Check Hardware\n"); return r; } /* Routine to Select clocks */ static int qca199x_clock_select(struct qca199x_dev *qca199x_dev) { int r = 0; if (!strcmp(qca199x_dev->clk_src_name, "BBCLK2")) { qca199x_dev->s_clk = clk_get(&qca199x_dev->client->dev, "ref_clk"); if (qca199x_dev->s_clk == NULL) goto err_invalid_dis_gpio; } else if (!strcmp(qca199x_dev->clk_src_name, "RFCLK3")) { qca199x_dev->s_clk = clk_get(&qca199x_dev->client->dev, "ref_clk_rf"); if (qca199x_dev->s_clk == NULL) goto err_invalid_dis_gpio; } else if (!strcmp(qca199x_dev->clk_src_name, "GPCLK")) { if (gpio_is_valid(qca199x_dev->clk_src_gpio)) { qca199x_dev->s_clk = clk_get(&qca199x_dev->client->dev, "core_clk"); if (qca199x_dev->s_clk == NULL) goto err_invalid_dis_gpio; } else { goto err_invalid_dis_gpio; } } else { qca199x_dev->s_clk = NULL; goto err_invalid_dis_gpio; } if (qca199x_dev->clk_run == false) { r = clk_prepare_enable(qca199x_dev->s_clk); if (r) goto err_invalid_clk; qca199x_dev->clk_run = true; } r = 0; return r; err_invalid_clk: r = -1; return r; err_invalid_dis_gpio: r = -2; return r; } /* Routine to De-Select clocks */ static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev) { int r = -1; if (qca199x_dev->s_clk != NULL) { if (qca199x_dev->clk_run == true) { clk_disable_unprepare(qca199x_dev->s_clk); qca199x_dev->clk_run = false; } return 0; } return r; } Loading @@ -755,9 +993,9 @@ static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata) if ((!gpio_is_valid(pdata->irq_gpio))) return -EINVAL; r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src); r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name); if (!strcmp(pdata->clk_src, "GPCLK")) if (!strcmp(pdata->clk_src_name, "GPCLK")) pdata->clk_src_gpio = of_get_named_gpio(np, "qcom,clk-en-gpio", 0); Loading @@ -771,7 +1009,6 @@ static int qca199x_probe(struct i2c_client *client, { int r = 0; int irqn = 0; struct clk *nfc_clk = NULL; struct device_node *node = client->dev.of_node; struct qca199x_platform_data *platform_data; struct qca199x_dev *qca199x_dev; Loading Loading @@ -809,12 +1046,13 @@ static int qca199x_probe(struct i2c_client *client, "nfc-nci probe: failed to allocate memory for module data\n"); return -ENOMEM; } qca199x_dev->client = client; if (gpio_is_valid(platform_data->irq_gpio)) { r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio"); if (r) { dev_err(&client->dev, "unable to request gpio [%d]\n", platform_data->irq_gpio); goto err_irq; goto err_free_dev; } r = gpio_direction_input(platform_data->irq_gpio); if (r) { Loading Loading @@ -842,7 +1080,7 @@ static int qca199x_probe(struct i2c_client *client, dev_err(&client->dev, "NFC: unable to request gpio [%d]\n", platform_data->dis_gpio); goto err_free_dev; goto err_irq; } r = gpio_direction_output(platform_data->dis_gpio, 1); if (r) { Loading @@ -855,32 +1093,17 @@ static int qca199x_probe(struct i2c_client *client, dev_err(&client->dev, "dis gpio not provided\n"); goto err_irq; } gpio_set_value(platform_data->dis_gpio, 1);/* HPD */ msleep(20); gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */ if (!strcmp(platform_data->clk_src, "BBCLK2")) { nfc_clk = clk_get(&client->dev, "ref_clk"); if (nfc_clk == NULL) goto err_dis_gpio; } else if (!strcmp(platform_data->clk_src, "RFCLK3")) { nfc_clk = clk_get(&client->dev, "ref_clk_rf"); if (nfc_clk == NULL) goto err_dis_gpio; } else if (!strcmp(platform_data->clk_src, "GPCLK")) { if (gpio_is_valid(platform_data->clk_src_gpio)) { nfc_clk = clk_get(&client->dev, "core_clk"); if (nfc_clk == NULL) goto err_dis_gpio; } else { /* Get the clock source name and gpio from from Device Tree */ qca199x_dev->clk_src_name = platform_data->clk_src_name; qca199x_dev->clk_src_gpio = platform_data->clk_src_gpio; qca199x_dev->clk_run = false; r = qca199x_clock_select(qca199x_dev); if (r != 0) { if (r == -1) goto err_clk; else goto err_dis_gpio; } } else { nfc_clk = NULL; } r = clk_prepare_enable(nfc_clk); if (r) goto err_clk; platform_data->ven_gpio = of_get_named_gpio(node, "qcom,clk-gpio", 0); Loading @@ -893,7 +1116,6 @@ static int qca199x_probe(struct i2c_client *client, } r = gpio_direction_input(platform_data->ven_gpio); if (r) { dev_err(&client->dev, "unable to set direction for gpio [%d]\n", platform_data->ven_gpio); Loading @@ -906,7 +1128,6 @@ static int qca199x_probe(struct i2c_client *client, qca199x_dev->dis_gpio = platform_data->dis_gpio; qca199x_dev->irq_gpio = platform_data->irq_gpio; qca199x_dev->ven_gpio = platform_data->ven_gpio; qca199x_dev->client = client; /* init mutex and queues */ init_waitqueue_head(&qca199x_dev->read_wq); Loading Loading @@ -941,12 +1162,6 @@ static int qca199x_probe(struct i2c_client *client, * for reading. It is cleared when all data has been read. */ device_mode.handle_flavour = UNSOLICITED_MODE; r = nfcc_initialise(client, platform_data->reg); if (r) { dev_err(&client->dev, "nfc-nci probe: request nfcc initialise failed\n"); goto err_nfcc_init_failed; } qca199x_dev->irq_enabled = true; r = request_irq(client->irq, qca199x_dev_irq_handler, IRQF_TRIGGER_RISING, client->name, qca199x_dev); Loading @@ -956,12 +1171,12 @@ static int qca199x_probe(struct i2c_client *client, } qca199x_disable_irq(qca199x_dev); i2c_set_clientdata(client, qca199x_dev); gpio_set_value(platform_data->dis_gpio, 1); dev_dbg(&client->dev, "nfc-nci probe: %s, probing qca1990 exited successfully\n", __func__); return 0; err_nfcc_init_failed: err_request_irq_failed: misc_deregister(&qca199x_dev->qca199x_device); err_misc_register: Loading @@ -969,12 +1184,12 @@ err_misc_register: err_ven_gpio: gpio_free(platform_data->ven_gpio); err_clk: clk_disable_unprepare(nfc_clk); qca199x_clock_deselect(qca199x_dev); err_dis_gpio: r = gpio_direction_input(platform_data->dis_gpio); if (r) dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); if (!strcmp(platform_data->clk_src, "GPCLK")) { if (!strcmp(platform_data->clk_src_name, "GPCLK")) { r = gpio_direction_input(platform_data->clk_src_gpio); if (r) dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); Loading Loading
drivers/nfc/nfc-nci.c +276 −61 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ struct qca199x_platform_data { unsigned int dis_gpio; unsigned int ven_gpio; unsigned int reg; const char *clk_src; const char *clk_src_name; unsigned int clk_src_gpio; }; Loading @@ -45,14 +45,18 @@ static struct of_device_id msm_match_table[] = { MODULE_DEVICE_TABLE(of, msm_match_table); #define MAX_BUFFER_SIZE (780) #define PACKET_MAX_LENGTH (258) /* Read data */ #define PACKET_HEADER_SIZE_NCI (4) #define PACKET_TYPE_NCI (16) #define MAX_PACKET_SIZE (PACKET_HEADER_SIZE_NCI + 255) #define MAX_QCA_REG (116) /* will timeout in approx. 100ms as 10us steps */ #define NTF_TIMEOUT (10000) #define CORE_RESET_RSP_GID (0x60) #define CORE_RESET_OID (0x00) #define CORE_RST_NTF_LENGTH (0x02) static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len); static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr); struct qca199x_dev { wait_queue_head_t read_wq; Loading @@ -63,11 +67,23 @@ struct qca199x_dev { unsigned int dis_gpio; unsigned int ven_gpio; bool irq_enabled; bool sent_first_nci_write; spinlock_t irq_enabled_lock; unsigned int count_irq; enum nfcc_state state; unsigned int clk_src_gpio; const char *clk_src_name; struct clk *s_clk; bool clk_run; }; static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len); static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr); static int qca199x_clock_select(struct qca199x_dev *qca199x_dev); static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev); /* * To allow filtering of nfc logging from user. This is set via * IOCTL NFC_KERNEL_LOGGING_MODE. Loading Loading @@ -205,24 +221,34 @@ static ssize_t nfc_read(struct file *filp, char __user *buf, /* NORMAL NCI Behaviour */ /* Read the header */ ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH); /* We ignore all packets of length PAYLOAD_HEADER_LENGTH or less (i.e <=3). In this case return a total length of ZERO. So ALL PACKETS MUST HAVE A PAYLOAD. If ret < 0 then this is an error code. */ if (ret != PAYLOAD_HEADER_LENGTH) { if (ret < 0) total = ret; else total = 0; goto err; } length = len[PAYLOAD_HEADER_LENGTH - 1]; if (length == 0) total = 0; if (length == 0) { ret = 0; total = ret; goto err; } /** make sure full packet fits in the buffer **/ if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) { /* Read the packet */ ret = i2c_master_recv(qca199x_dev->client, tmp, (length + PAYLOAD_HEADER_LENGTH)); if (ret < 0) { total = 0; total = ret; if (ret < 0) goto err; } total = (length + PAYLOAD_HEADER_LENGTH); } if (total > 0) { if ((total > count) || copy_to_user(buf, tmp, total)) { Loading @@ -232,14 +258,57 @@ static ssize_t nfc_read(struct file *filp, char __user *buf, total = -EFAULT; } } mutex_unlock(&qca199x_dev->read_mutex); err: if (ret < 0) mutex_unlock(&qca199x_dev->read_mutex); done: return total; } /* Local routine to read from nfcc buffer. This is called to clear any pending receive messages in the nfcc's read buffer, which may be there following a POR. In this way, the upper layers (Device Transport) will associate the next rsp/ntf nci message with the next nci command to the nfcc. Otherwise, the DT may interpret a ntf from the nfcc as being from the nci core reset command when in fact it was already present in the nfcc read buffer following a POR. */ int nfcc_read_buff_svc(struct qca199x_dev *qca199x_dev) { unsigned char tmp[PACKET_MAX_LENGTH]; unsigned char len[PAYLOAD_HEADER_LENGTH]; int total, length, ret; total = 0; length = 0; mutex_lock(&qca199x_dev->read_mutex); memset(tmp, 0, sizeof(tmp)); memset(len, 0, sizeof(len)); /* Read the header */ ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH); if (ret < PAYLOAD_HEADER_LENGTH) { total = ret; goto leave; } length = len[PAYLOAD_HEADER_LENGTH - 1]; if (length == 0) { ret = PAYLOAD_HEADER_LENGTH; total = ret; goto leave; } /** make sure full packet fits in the buffer **/ if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= PACKET_MAX_LENGTH)) { /* Read the packet */ ret = i2c_master_recv(qca199x_dev->client, tmp, (length + PAYLOAD_HEADER_LENGTH)); total = ret; } leave: mutex_unlock(&qca199x_dev->read_mutex); return total; } static ssize_t nfc_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { Loading @@ -247,6 +316,7 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf, char tmp[MAX_BUFFER_SIZE]; int ret = 0; enum ehandler_mode dmode; int nfcc_buffer = 0; if (count > MAX_BUFFER_SIZE) { dev_err(&qca199x_dev->client->dev, "out of memory\n"); Loading @@ -257,6 +327,24 @@ static ssize_t nfc_write(struct file *filp, const char __user *buf, "nfc-nci write: failed to copy from user space\n"); return -EFAULT; } /* A catch for when the DT is sending the initial NCI write following a hardware POR. In this case we should clear any pending messages in nfcc buffer and open the interrupt gate for new messages coming from the nfcc. */ if ((qca199x_dev->sent_first_nci_write == false) && (qca199x_dev->irq_enabled == false)) { /* check rsp/ntf from nfcc read-side buffer */ nfcc_buffer = nfcc_read_buff_svc(qca199x_dev); /* There has been an error while reading from nfcc */ if (nfcc_buffer < 0) { dev_err(&qca199x_dev->client->dev, "nfc-nci write: error while servicing nfcc read buffer\n"); } qca199x_dev->sent_first_nci_write = true; qca199x_enable_irq(qca199x_dev); } mutex_lock(&qca199x_dev->read_mutex); dmode = device_mode.handle_flavour; /* FTM-DIRECT-I2C RD/WR MODE */ Loading Loading @@ -378,6 +466,9 @@ int nfc_ioctl_power_states(struct file *filp, unsigned int cmd, struct qca199x_dev *qca199x_dev = filp->private_data; if (arg == 0) { r = qca199x_clock_select(qca199x_dev); if (r < 0) goto err_req; gpio_set_value(qca199x_dev->dis_gpio, 0); r = gpio_direction_output(qca199x_dev->dis_gpio, 1); if (r) { Loading @@ -389,6 +480,23 @@ int nfc_ioctl_power_states(struct file *filp, unsigned int cmd, gpio_set_value(qca199x_dev->dis_gpio, 0); msleep(20); } else if (arg == 1) { /* We are attempting a hardware reset so let us disable interrupts to avoid spurious notifications to upper layers. */ qca199x_disable_irq(qca199x_dev); /* Deselection of clock */ r = qca199x_clock_deselect(qca199x_dev); if (r < 0) goto err_req; /* Also, set flag for initial NCI write following resetas may wish to do some house keeping. Ensure no pending messages in NFCC buffers which may be wrongly construed as response to initial message */ qca199x_dev->sent_first_nci_write = false; gpio_set_value(qca199x_dev->dis_gpio, 0); r = gpio_direction_output(qca199x_dev->dis_gpio, 1); if (r) { Loading @@ -402,10 +510,12 @@ int nfc_ioctl_power_states(struct file *filp, unsigned int cmd, } else if (arg == 2) { mutex_lock(&qca199x_dev->read_mutex); r = nfcc_initialise(qca199x_dev->client, 0xE); /* Also reset first NCI write */ qca199x_dev->sent_first_nci_write = false; mutex_unlock(&qca199x_dev->read_mutex); if (r) { dev_err(&qca199x_dev->client->dev, "nfc-nci probe: request nfcc initialise failed\n"); "nfc_ioctl_power_states: request nfcc initialise failed\n"); goto err_req; } } else if (arg == 3) { Loading Loading @@ -536,8 +646,6 @@ invalid_wr: return raw_chip_version; } /* * Inside nfc_ioctl_kernel_logging * Loading Loading @@ -664,72 +772,202 @@ static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr) unsigned char raw_1P8_PAD_CFG_CLK_REQ[] = {0xA5, 0x1}; unsigned char raw_1P8_PAD_CFG_PWR_REQ[] = {0xA7, 0x1}; unsigned char buf = 0; bool core_reset_completed = false; unsigned char rsp[6]; int time_taken = 0; int ret = 0; client->addr = curr_addr; r = i2c_master_send(client, &buf, 1); if (r < 0) goto err_init; buf = 0; r = i2c_master_recv(client, &buf, 1); if (r < 0) goto err_init; if (0x10 != (0x10 & buf)) { RAW(s73, 0x02); r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73)); if (r < 0) goto err_init; usleep(1000); RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01); r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0], sizeof(raw_1p8_CONTROL_011)); if (r < 0) goto err_init; usleep(1000); RAW(1P8_CONTROL_010, (0x8)); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(10000); /* 10ms wait */ RAW(1P8_CONTROL_010, (0xC)); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(100); /* 100uS wait */ RAW(1P8_X0_0B0, (FREQ_SEL_19)); r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0], sizeof(raw_1P8_X0_0B0)); if (r < 0) goto err_init; usleep(1000); /* PWR_EN = 1 */ RAW(1P8_CONTROL_010, (0xd)); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(20000); /* 20ms wait */ /* LS_EN = 1 */ RAW(1P8_CONTROL_010, 0xF); r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0], sizeof(raw_1P8_CONTROL_010)); if (r < 0) goto err_init; usleep(20000); /* 20ms wait */ /* Enable the PMIC clock */ RAW(1P8_PAD_CFG_CLK_REQ, (0x1)); r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0], sizeof(raw_1P8_PAD_CFG_CLK_REQ)); if (r < 0) goto err_init; usleep(1000); RAW(1P8_PAD_CFG_PWR_REQ, (0x1)); r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0], sizeof(raw_1P8_PAD_CFG_PWR_REQ)); if (r < 0) goto err_init; usleep(1000); RAW(slave2, 0x10); r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2)); if (r < 0) goto err_init; usleep(1000); RAW(slave1, NCI_I2C_SLAVE); r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1)); if (r < 0) goto err_init; usleep(1000); /* QCA199x NFCC CPU should now boot... */ r = i2c_master_recv(client, &raw_slave1_rd, 1); /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/ client->addr = NCI_I2C_SLAVE; /* Start with small delay and then we will poll until we get a core reset notification - This is time for chip & NFCC controller to come-up. */ usleep(1000); /* 1 ms */ do { ret = i2c_master_recv(client, rsp, 5); /* Found core reset notification */ if (((rsp[0] == CORE_RESET_RSP_GID) && (rsp[1] == CORE_RESET_OID) && (rsp[2] == CORE_RST_NTF_LENGTH)) || time_taken == NTF_TIMEOUT) { core_reset_completed = true; } usleep(10); /* 10us sleep before retry */ time_taken++; } while (!core_reset_completed); r = 0; } else { goto err_init; } return r; err_init: r = 1; dev_err(&client->dev, "nfc-nci nfcc_initialise: failed. Check Hardware\n"); return r; } /* Routine to Select clocks */ static int qca199x_clock_select(struct qca199x_dev *qca199x_dev) { int r = 0; if (!strcmp(qca199x_dev->clk_src_name, "BBCLK2")) { qca199x_dev->s_clk = clk_get(&qca199x_dev->client->dev, "ref_clk"); if (qca199x_dev->s_clk == NULL) goto err_invalid_dis_gpio; } else if (!strcmp(qca199x_dev->clk_src_name, "RFCLK3")) { qca199x_dev->s_clk = clk_get(&qca199x_dev->client->dev, "ref_clk_rf"); if (qca199x_dev->s_clk == NULL) goto err_invalid_dis_gpio; } else if (!strcmp(qca199x_dev->clk_src_name, "GPCLK")) { if (gpio_is_valid(qca199x_dev->clk_src_gpio)) { qca199x_dev->s_clk = clk_get(&qca199x_dev->client->dev, "core_clk"); if (qca199x_dev->s_clk == NULL) goto err_invalid_dis_gpio; } else { goto err_invalid_dis_gpio; } } else { qca199x_dev->s_clk = NULL; goto err_invalid_dis_gpio; } if (qca199x_dev->clk_run == false) { r = clk_prepare_enable(qca199x_dev->s_clk); if (r) goto err_invalid_clk; qca199x_dev->clk_run = true; } r = 0; return r; err_invalid_clk: r = -1; return r; err_invalid_dis_gpio: r = -2; return r; } /* Routine to De-Select clocks */ static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev) { int r = -1; if (qca199x_dev->s_clk != NULL) { if (qca199x_dev->clk_run == true) { clk_disable_unprepare(qca199x_dev->s_clk); qca199x_dev->clk_run = false; } return 0; } return r; } Loading @@ -755,9 +993,9 @@ static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata) if ((!gpio_is_valid(pdata->irq_gpio))) return -EINVAL; r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src); r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name); if (!strcmp(pdata->clk_src, "GPCLK")) if (!strcmp(pdata->clk_src_name, "GPCLK")) pdata->clk_src_gpio = of_get_named_gpio(np, "qcom,clk-en-gpio", 0); Loading @@ -771,7 +1009,6 @@ static int qca199x_probe(struct i2c_client *client, { int r = 0; int irqn = 0; struct clk *nfc_clk = NULL; struct device_node *node = client->dev.of_node; struct qca199x_platform_data *platform_data; struct qca199x_dev *qca199x_dev; Loading Loading @@ -809,12 +1046,13 @@ static int qca199x_probe(struct i2c_client *client, "nfc-nci probe: failed to allocate memory for module data\n"); return -ENOMEM; } qca199x_dev->client = client; if (gpio_is_valid(platform_data->irq_gpio)) { r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio"); if (r) { dev_err(&client->dev, "unable to request gpio [%d]\n", platform_data->irq_gpio); goto err_irq; goto err_free_dev; } r = gpio_direction_input(platform_data->irq_gpio); if (r) { Loading Loading @@ -842,7 +1080,7 @@ static int qca199x_probe(struct i2c_client *client, dev_err(&client->dev, "NFC: unable to request gpio [%d]\n", platform_data->dis_gpio); goto err_free_dev; goto err_irq; } r = gpio_direction_output(platform_data->dis_gpio, 1); if (r) { Loading @@ -855,32 +1093,17 @@ static int qca199x_probe(struct i2c_client *client, dev_err(&client->dev, "dis gpio not provided\n"); goto err_irq; } gpio_set_value(platform_data->dis_gpio, 1);/* HPD */ msleep(20); gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */ if (!strcmp(platform_data->clk_src, "BBCLK2")) { nfc_clk = clk_get(&client->dev, "ref_clk"); if (nfc_clk == NULL) goto err_dis_gpio; } else if (!strcmp(platform_data->clk_src, "RFCLK3")) { nfc_clk = clk_get(&client->dev, "ref_clk_rf"); if (nfc_clk == NULL) goto err_dis_gpio; } else if (!strcmp(platform_data->clk_src, "GPCLK")) { if (gpio_is_valid(platform_data->clk_src_gpio)) { nfc_clk = clk_get(&client->dev, "core_clk"); if (nfc_clk == NULL) goto err_dis_gpio; } else { /* Get the clock source name and gpio from from Device Tree */ qca199x_dev->clk_src_name = platform_data->clk_src_name; qca199x_dev->clk_src_gpio = platform_data->clk_src_gpio; qca199x_dev->clk_run = false; r = qca199x_clock_select(qca199x_dev); if (r != 0) { if (r == -1) goto err_clk; else goto err_dis_gpio; } } else { nfc_clk = NULL; } r = clk_prepare_enable(nfc_clk); if (r) goto err_clk; platform_data->ven_gpio = of_get_named_gpio(node, "qcom,clk-gpio", 0); Loading @@ -893,7 +1116,6 @@ static int qca199x_probe(struct i2c_client *client, } r = gpio_direction_input(platform_data->ven_gpio); if (r) { dev_err(&client->dev, "unable to set direction for gpio [%d]\n", platform_data->ven_gpio); Loading @@ -906,7 +1128,6 @@ static int qca199x_probe(struct i2c_client *client, qca199x_dev->dis_gpio = platform_data->dis_gpio; qca199x_dev->irq_gpio = platform_data->irq_gpio; qca199x_dev->ven_gpio = platform_data->ven_gpio; qca199x_dev->client = client; /* init mutex and queues */ init_waitqueue_head(&qca199x_dev->read_wq); Loading Loading @@ -941,12 +1162,6 @@ static int qca199x_probe(struct i2c_client *client, * for reading. It is cleared when all data has been read. */ device_mode.handle_flavour = UNSOLICITED_MODE; r = nfcc_initialise(client, platform_data->reg); if (r) { dev_err(&client->dev, "nfc-nci probe: request nfcc initialise failed\n"); goto err_nfcc_init_failed; } qca199x_dev->irq_enabled = true; r = request_irq(client->irq, qca199x_dev_irq_handler, IRQF_TRIGGER_RISING, client->name, qca199x_dev); Loading @@ -956,12 +1171,12 @@ static int qca199x_probe(struct i2c_client *client, } qca199x_disable_irq(qca199x_dev); i2c_set_clientdata(client, qca199x_dev); gpio_set_value(platform_data->dis_gpio, 1); dev_dbg(&client->dev, "nfc-nci probe: %s, probing qca1990 exited successfully\n", __func__); return 0; err_nfcc_init_failed: err_request_irq_failed: misc_deregister(&qca199x_dev->qca199x_device); err_misc_register: Loading @@ -969,12 +1184,12 @@ err_misc_register: err_ven_gpio: gpio_free(platform_data->ven_gpio); err_clk: clk_disable_unprepare(nfc_clk); qca199x_clock_deselect(qca199x_dev); err_dis_gpio: r = gpio_direction_input(platform_data->dis_gpio); if (r) dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); if (!strcmp(platform_data->clk_src, "GPCLK")) { if (!strcmp(platform_data->clk_src_name, "GPCLK")) { r = gpio_direction_input(platform_data->clk_src_gpio); if (r) dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n"); Loading