예제 #1
0
/*
 * request_locality request the TPM locality
 * @param: chip, the chip description
 * @return: the active locality or EACCESS.
 */
static int request_locality(struct tpm_chip *chip)
{
	unsigned long stop;
	long ret;
	struct tpm_stm_dev *tpm_dev;
	u8 data;

	if (check_locality(chip) == chip->vendor.locality)
		return chip->vendor.locality;

	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);

	data = TPM_ACCESS_REQUEST_USE;
	ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
	if (ret < 0)
		goto end;

	stop = jiffies + chip->vendor.timeout_a;

	/* Request locality is usually effective after the request */
	do {
		if (check_locality(chip) >= 0)
			return chip->vendor.locality;
		msleep(TPM_TIMEOUT);
	} while (time_before(jiffies, stop));
	ret = -EACCES;
end:
	return ret;
} /* request_locality() */
예제 #2
0
/*
 * request_locality request the TPM locality
 * @param: chip, the chip description
 * @return: the active locality or EACCESS.
 */
static int request_locality(struct tpm_chip *chip)
{
	unsigned long stop;
	long rc;
	struct i2c_client *client;
	u8 data;

	client = (struct i2c_client *) TPM_VPRIV(chip);

	if (check_locality(chip) == chip->vendor.locality)
		return chip->vendor.locality;

	data = TPM_ACCESS_REQUEST_USE;
	rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
	if (rc < 0)
		goto end;

	if (chip->vendor.irq) {
		rc = wait_for_serirq_timeout(chip, (check_locality
						       (chip) >= 0),
						      chip->vendor.timeout_a);
		if (rc > 0)
			return chip->vendor.locality;
	} else{
		stop = jiffies + chip->vendor.timeout_a;
		do {
			if (check_locality(chip) >= 0)
				return chip->vendor.locality;
			msleep(TPM_TIMEOUT);
		} while (time_before(jiffies, stop));
	}
	rc = -EACCES;
end:
	return rc;
} /* request_locality() */
예제 #3
0
/*
 * clear_interruption
 * clear the TPM interrupt register.
 * @param: tpm, the chip description
 */
static void clear_interruption(struct i2c_client *client)
{
	u8 interrupt;
	I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
	I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1);
	I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
} /* clear_interruption() */
예제 #4
0
void
ti_iic_do_write(struct ti_iic_softc *sc, uint32_t stat)
{
	int len;

	DPRINTF(("ti_iic_do_write stat %#x\n", stat));

	if (stat & I2C_IRQSTATUS_XDR) {
		len = I2C_READ_REG(sc, AM335X_I2C_BUFSTAT);
		len = I2C_BUFSTAT_TXSTAT(len);
		DPRINTF(("ti_iic_do_write xmit drain len %d left %d\n",
		    len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
	} else if (stat & I2C_IRQSTATUS_XRDY) {
		len = sc->sc_txthres + 1;
		DPRINTF(("ti_iic_do_write xmit len %d left %d\n",
		    len, I2C_READ_REG(sc, AM335X_I2C_CNT)));
	}
	for (;
	    sc->sc_bufidx < sc->sc_buflen && len > 0;
	    sc->sc_bufidx++, len--) {
		DPRINTF(("ti_iic_do_write send b[%d]=0x%x\n",
		    sc->sc_bufidx, sc->sc_buf[sc->sc_bufidx]));
		I2C_WRITE_DATA(sc, sc->sc_buf[sc->sc_bufidx]);
	}
	DPRINTF(("ti_iic_do_write done\n"));
}
예제 #5
0
/*
 * clear_interruption
 * clear the TPM interrupt register.
 * @param: tpm, the chip description
 * @return: the TPM_INT_STATUS value
 */
static u8 clear_interruption(struct tpm_stm_dev *tpm_dev)
{
	u8 interrupt;

	I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
	I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
	return interrupt;
} /* clear_interruption() */
예제 #6
0
/*
 * release_locality release the active locality
 * @param: chip, the tpm chip description.
 */
static void release_locality(struct tpm_chip *chip)
{
	struct i2c_client *client;
	u8 data;

	client = (struct i2c_client *) TPM_VPRIV(chip);
	data = TPM_ACCESS_ACTIVE_LOCALITY;

	I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
}
예제 #7
0
/*
 * release_locality release the active locality
 * @param: chip, the tpm chip description.
 */
static void release_locality(struct tpm_chip *chip)
{
	struct tpm_stm_dev *tpm_dev;
	u8 data;

	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
	data = TPM_ACCESS_ACTIVE_LOCALITY;

	I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
}
예제 #8
0
/*
 * tpm_stm_i2c_cancel, cancel is not implemented.
 * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
 */
static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
{
	struct tpm_stm_dev *tpm_dev;
	u8 data;

	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);

	data = TPM_STS_COMMAND_READY;
	I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
} /* tpm_stm_i2c_cancel() */
예제 #9
0
/*
 * tpm_stm_i2c_cancel, cancel is not implemented.
 * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
 */
static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
{
	struct i2c_client *client;
	u8 data;

	client = (struct i2c_client *) TPM_VPRIV(chip);

	data = TPM_STS_COMMAND_READY;
	I2C_WRITE_DATA(client, TPM_STS, &data, 1);
	if (chip->vendor.irq)
		wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a);
}	/* tpm_stm_i2c_cancel() */
예제 #10
0
/*
 * 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;
}
예제 #11
0
/*
 * tpm_stm_i2c_send send TPM commands through the I2C bus.
 *
 * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
 * @param: buf,	the buffer to send.
 * @param: count, the number of bytes to send.
 * @return: In case of success the number of bytes sent.
 *			In other case, a < 0 value describing the issue.
 */
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
			    size_t len)
{
	u32 status,
	    burstcnt = 0, i, size;
	int ret;
	u8 data;
	struct i2c_client *client;

	if (chip == NULL)
		return -EBUSY;
	if (len < TPM_HEADER_SIZE)
		return -EBUSY;

	client = (struct i2c_client *)TPM_VPRIV(chip);

	client->flags = 0;

	ret = request_locality(chip);
	if (ret < 0)
		return ret;

	status = tpm_stm_i2c_status(chip);
	if ((status & TPM_STS_COMMAND_READY) == 0) {
		tpm_stm_i2c_cancel(chip);
		if (wait_for_stat
		    (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
		     &chip->vendor.int_queue) < 0) {
			ret = -ETIME;
			goto out_err;
		}
	}

	for (i = 0 ; i < len - 1 ;) {
		burstcnt = get_burstcount(chip);
		size = min_t(int, len - i - 1, burstcnt);
		ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
		if (ret < 0)
			goto out_err;

		i += size;
	}

	status = tpm_stm_i2c_status(chip);
	if ((status & TPM_STS_DATA_EXPECT) == 0) {
		ret = -EIO;
		goto out_err;
	}

	ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1);
	if (ret < 0)
		goto out_err;

	status = tpm_stm_i2c_status(chip);
	if ((status & TPM_STS_DATA_EXPECT) != 0) {
		ret = -EIO;
		goto out_err;
	}

	data = TPM_STS_GO;
	I2C_WRITE_DATA(client, TPM_STS, &data, 1);

	return len;
out_err:
	tpm_stm_i2c_cancel(chip);
	release_locality(chip);
	return ret;
}
예제 #12
0
/*
 * 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;
}