/* * wait_for_stat wait for a TPM_STS value * @param: chip, the tpm chip description * @param: mask, the value mask to wait * @param: timeout, the timeout * @param: queue, the wait queue. * @param: check_cancel, does the command can be cancelled ? * @return: the tpm status, 0 if success, -ETIME if timeout is reached. */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue, bool check_cancel) { unsigned long stop; int ret; bool canceled = false; bool condition; u32 cur_intrs; u8 interrupt, status; struct tpm_stm_dev *tpm_dev; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); /* check current status */ status = tpm_stm_i2c_status(chip); if ((status & mask) == mask) return 0; stop = jiffies + timeout; if (chip->vendor.irq) { cur_intrs = tpm_dev->intrs; interrupt = clear_interruption(tpm_dev); enable_irq(chip->vendor.irq); again: timeout = stop - jiffies; if ((long) timeout <= 0) return -1; ret = wait_event_interruptible_timeout(*queue, cur_intrs != tpm_dev->intrs, timeout); interrupt |= clear_interruption(tpm_dev); status = interrupt_to_status(interrupt); condition = wait_for_tpm_stat_cond(chip, mask, check_cancel, &canceled); if (ret >= 0 && condition) { if (canceled) return -ECANCELED; return 0; } if (ret == -ERESTARTSYS && freezing(current)) { clear_thread_flag(TIF_SIGPENDING); goto again; } disable_irq_nosync(chip->vendor.irq); } else { do { msleep(TPM_TIMEOUT); status = chip->ops->status(chip); if ((status & mask) == mask) return 0; } while (time_before(jiffies, stop)); } return -ETIME; } /* wait_for_stat() */
/* * wait_for_stat wait for a TPM_STS value * @param: chip, the tpm chip description * @param: mask, the value mask to wait * @param: timeout, the timeout * @param: queue, the wait queue. * @param: check_cancel, does the command can be cancelled ? * @return: the tpm status, 0 if success, -ETIME if timeout is reached. */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue, bool check_cancel) { struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); unsigned long stop; int ret = 0; bool canceled = false; bool condition; u32 cur_intrs; u8 status; /* check current status */ status = st33zp24_status(chip); if ((status & mask) == mask) return 0; stop = jiffies + timeout; if (chip->flags & TPM_CHIP_FLAG_IRQ) { cur_intrs = tpm_dev->intrs; clear_interruption(tpm_dev); enable_irq(tpm_dev->irq); do { if (ret == -ERESTARTSYS && freezing(current)) clear_thread_flag(TIF_SIGPENDING); timeout = stop - jiffies; if ((long) timeout <= 0) return -1; ret = wait_event_interruptible_timeout(*queue, cur_intrs != tpm_dev->intrs, timeout); clear_interruption(tpm_dev); condition = wait_for_tpm_stat_cond(chip, mask, check_cancel, &canceled); if (ret >= 0 && condition) { if (canceled) return -ECANCELED; return 0; } } while (ret == -ERESTARTSYS && freezing(current)); disable_irq_nosync(tpm_dev->irq); } else { do { msleep(TPM_TIMEOUT); status = chip->ops->status(chip); if ((status & mask) == mask) return 0; } while (time_before(jiffies, stop)); } return -ETIME; } /* wait_for_stat() */
static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, unsigned long timeout) { int status = 2; struct i2c_client *client; client = (struct i2c_client *) TPM_VPRIV(chip); status = _wait_for_interrupt_serirq_timeout(chip, timeout); if (!status) { status = -EBUSY; } else{ clear_interruption(client); if (condition) status = 1; } return status; }
/* * tpm_st33_i2c_probe initialize the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: id, the i2c_device_id struct. * @return: 0 in case of success. * -1 in other case. */ static int tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; u8 intmask; struct tpm_chip *chip; struct st33zp24_platform_data *platform_data; if (client == NULL) { pr_info("%s: i2c client is NULL. Device not accessible.\n", __func__); err = -ENODEV; goto end; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_info(&client->dev, "client not i2c capable\n"); err = -ENODEV; goto end; } chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); if (!chip) { dev_info(&client->dev, "fail chip\n"); err = -ENODEV; goto end; } platform_data = client->dev.platform_data; if (!platform_data) { dev_info(&client->dev, "chip not available\n"); err = -ENODEV; goto _tpm_clean_answer; } platform_data->tpm_i2c_buffer[0] = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); if (platform_data->tpm_i2c_buffer[0] == NULL) { err = -ENOMEM; goto _tpm_clean_answer; } platform_data->tpm_i2c_buffer[1] = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); if (platform_data->tpm_i2c_buffer[1] == NULL) { err = -ENOMEM; goto _tpm_clean_response1; } TPM_VPRIV(chip) = client; chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.locality = LOCALITY0; if (power_mgt) { err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); if (err) goto _gpio_init1; gpio_set_value(platform_data->io_lpcpd, 1); } if (interrupts) { init_completion(&platform_data->irq_detection); if (request_locality(chip) != LOCALITY0) { err = -ENODEV; goto _tpm_clean_response2; } err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ"); if (err) goto _gpio_init2; clear_interruption(client); err = request_irq(gpio_to_irq(platform_data->io_serirq), &tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (err < 0) { dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", gpio_to_irq(platform_data->io_serirq)); goto _irq_set; } err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1); if (err < 0) goto _irq_set; intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_FIFO_AVALAIBLE_INT | TPM_INTF_WAKE_UP_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1); if (err < 0) goto _irq_set; intmask = TPM_GLOBAL_INT_ENABLE; err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1); if (err < 0) goto _irq_set; err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1); if (err < 0) goto _irq_set; chip->vendor.irq = interrupts; tpm_gen_interrupt(chip); } tpm_get_timeouts(chip); i2c_set_clientdata(client, chip); dev_info(chip->dev, "TPM I2C Initialized\n"); return 0; _irq_set: free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip); _gpio_init2: if (interrupts) gpio_free(platform_data->io_serirq); _gpio_init1: if (power_mgt) gpio_free(platform_data->io_lpcpd); _tpm_clean_response2: kzfree(platform_data->tpm_i2c_buffer[1]); platform_data->tpm_i2c_buffer[1] = NULL; _tpm_clean_response1: kzfree(platform_data->tpm_i2c_buffer[0]); platform_data->tpm_i2c_buffer[0] = NULL; _tpm_clean_answer: tpm_remove_hardware(chip->dev); end: pr_info("TPM I2C initialisation fail\n"); return err; }
/* * st33zp24_probe initialize the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: id, the i2c_device_id struct. * @return: 0 in case of success. * -1 in other case. */ int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, struct device *dev, int irq, int io_lpcpd) { int ret; u8 intmask = 0; struct tpm_chip *chip; struct st33zp24_dev *tpm_dev; chip = tpmm_chip_alloc(dev, &st33zp24_tpm); if (IS_ERR(chip)) return PTR_ERR(chip); tpm_dev = devm_kzalloc(dev, sizeof(struct st33zp24_dev), GFP_KERNEL); if (!tpm_dev) return -ENOMEM; tpm_dev->phy_id = phy_id; tpm_dev->ops = ops; dev_set_drvdata(&chip->dev, tpm_dev); chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); chip->timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); tpm_dev->locality = LOCALITY0; if (irq) { /* INTERRUPT Setup */ init_waitqueue_head(&tpm_dev->read_queue); tpm_dev->intrs = 0; if (request_locality(chip) != LOCALITY0) { ret = -ENODEV; goto _tpm_clean_answer; } clear_interruption(tpm_dev); ret = devm_request_irq(dev, irq, tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (ret < 0) { dev_err(&chip->dev, "TPM SERIRQ signals %d not available\n", irq); goto _tpm_clean_answer; } intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_ENABLE, &intmask, 1); if (ret < 0) goto _tpm_clean_answer; intmask = TPM_GLOBAL_INT_ENABLE; ret = tpm_dev->ops->send(tpm_dev->phy_id, (TPM_INT_ENABLE + 3), &intmask, 1); if (ret < 0) goto _tpm_clean_answer; tpm_dev->irq = irq; chip->flags |= TPM_CHIP_FLAG_IRQ; disable_irq_nosync(tpm_dev->irq); } return tpm_chip_register(chip); _tpm_clean_answer: dev_info(&chip->dev, "TPM initialization fail\n"); return ret; }
/* * tpm_stm_i2c_probe initialize the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: id, the i2c_device_id struct. * @return: 0 in case of success. * -1 in other case. */ static int tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; u8 intmask = 0; struct tpm_chip *chip; struct st33zp24_platform_data *platform_data; struct tpm_stm_dev *tpm_dev; if (!client) { pr_info("%s: i2c client is NULL. Device not accessible.\n", __func__); return -ENODEV; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_info(&client->dev, "client not i2c capable\n"); return -ENODEV; } tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), GFP_KERNEL); if (!tpm_dev) return -ENOMEM; chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm); if (IS_ERR(chip)) return PTR_ERR(chip); TPM_VPRIV(chip) = tpm_dev; tpm_dev->client = client; platform_data = client->dev.platform_data; if (!platform_data && client->dev.of_node) { ret = tpm_stm_i2c_of_request_resources(chip); if (ret) goto _tpm_clean_answer; } else if (platform_data) { ret = tpm_stm_i2c_request_resources(client, chip); if (ret) goto _tpm_clean_answer; } chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.locality = LOCALITY0; if (client->irq) { /* INTERRUPT Setup */ init_waitqueue_head(&chip->vendor.read_queue); tpm_dev->intrs = 0; if (request_locality(chip) != LOCALITY0) { ret = -ENODEV; goto _tpm_clean_answer; } clear_interruption(tpm_dev); ret = devm_request_irq(&client->dev, client->irq, tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (ret < 0) { dev_err(chip->pdev, "TPM SERIRQ signals %d not available\n", client->irq); goto _tpm_clean_answer; } intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); if (ret < 0) goto _tpm_clean_answer; intmask = TPM_GLOBAL_INT_ENABLE; ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), &intmask, 1); if (ret < 0) goto _tpm_clean_answer; chip->vendor.irq = client->irq; disable_irq_nosync(chip->vendor.irq); tpm_gen_interrupt(chip); } tpm_get_timeouts(chip); tpm_do_selftest(chip); return tpm_chip_register(chip); _tpm_clean_answer: dev_info(chip->pdev, "TPM I2C initialisation fail\n"); return ret; }