diff options
Diffstat (limited to 'drivers/crypto/atmel-sha204a.c')
| -rw-r--r-- | drivers/crypto/atmel-sha204a.c | 68 | 
1 files changed, 68 insertions, 0 deletions
| diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index c77f482d2a97..24ffdf505023 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -91,6 +91,62 @@ static int atmel_sha204a_rng_read(struct hwrng *rng, void *data, size_t max,  	return max;  } +static int atmel_sha204a_otp_read(struct i2c_client *client, u16 addr, u8 *otp) +{ +	struct atmel_i2c_cmd cmd; +	int ret = -1; + +	if (atmel_i2c_init_read_otp_cmd(&cmd, addr) < 0) { +		dev_err(&client->dev, "failed, invalid otp address %04X\n", +			addr); +		return ret; +	} + +	ret = atmel_i2c_send_receive(client, &cmd); + +	if (cmd.data[0] == 0xff) { +		dev_err(&client->dev, "failed, device not ready\n"); +		return -ret; +	} + +	memcpy(otp, cmd.data+1, 4); + +	return ret; +} + +static ssize_t otp_show(struct device *dev, +			struct device_attribute *attr, char *buf) +{ +	u16 addr; +	u8 otp[OTP_ZONE_SIZE]; +	char *str = buf; +	struct i2c_client *client = to_i2c_client(dev); +	int i; + +	for (addr = 0; addr < OTP_ZONE_SIZE/4; addr++) { +		if (atmel_sha204a_otp_read(client, addr, otp + addr * 4) < 0) { +			dev_err(dev, "failed to read otp zone\n"); +			break; +		} +	} + +	for (i = 0; i < addr*2; i++) +		str += sprintf(str, "%02X", otp[i]); +	str += sprintf(str, "\n"); +	return str - buf; +} +static DEVICE_ATTR_RO(otp); + +static struct attribute *atmel_sha204a_attrs[] = { +	&dev_attr_otp.attr, +	NULL +}; + +static const struct attribute_group atmel_sha204a_groups = { +	.name = "atsha204a", +	.attrs = atmel_sha204a_attrs, +}; +  static int atmel_sha204a_probe(struct i2c_client *client)  {  	struct atmel_i2c_client_priv *i2c_priv; @@ -111,6 +167,16 @@ static int atmel_sha204a_probe(struct i2c_client *client)  	if (ret)  		dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); +	/* otp read out */ +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) +		return -ENODEV; + +	ret = sysfs_create_group(&client->dev.kobj, &atmel_sha204a_groups); +	if (ret) { +		dev_err(&client->dev, "failed to register sysfs entry\n"); +		return ret; +	} +  	return ret;  } @@ -123,6 +189,8 @@ static void atmel_sha204a_remove(struct i2c_client *client)  		return;  	} +	sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups); +  	kfree((void *)i2c_priv->hwrng.priv);  } | 
