diff mbox

[U-Boot,v2,3/6] ARM: tegra: i2c: add nvec driver

Message ID 1398561270-25091-4-git-send-email-danindrey@mail.ru
State Deferred
Delegated to: Tom Warren
Headers show

Commit Message

Andrey Danin April 27, 2014, 1:14 a.m. UTC
Signed-off-by: Andrey Danin <danindrey@mail.ru>
CC: Stephen Warren <swarren@nvidia.com>
CC: Marc Dietrich <marvin24@gmx.de>
CC: Julian Andres Klode <jak@jak-linux.org>
CC: ac100@lists.launchpad.net
---
 Changes for v2:
	- NVEC driver was reworked to use tegra-i2c

 arch/arm/include/asm/arch-tegra/tegra_nvec.h |  130 ++++++++++++
 board/nvidia/common/board.c                  |   12 ++
 drivers/i2c/Makefile                         |    1 +
 drivers/i2c/tegra_nvec.c                     |  294 ++++++++++++++++++++++++++
 include/fdtdec.h                             |    1 +
 lib/fdtdec.c                                 |    1 +
 6 files changed, 439 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-tegra/tegra_nvec.h
 create mode 100644 drivers/i2c/tegra_nvec.c

Comments

Heiko Schocher April 29, 2014, 5:43 a.m. UTC | #1
Hello Andrey,

Am 27.04.2014 03:14, schrieb Andrey Danin:
> Signed-off-by: Andrey Danin<danindrey@mail.ru>
> CC: Stephen Warren<swarren@nvidia.com>
> CC: Marc Dietrich<marvin24@gmx.de>
> CC: Julian Andres Klode<jak@jak-linux.org>
> CC: ac100@lists.launchpad.net
> ---
>   Changes for v2:
> 	- NVEC driver was reworked to use tegra-i2c
>
>   arch/arm/include/asm/arch-tegra/tegra_nvec.h |  130 ++++++++++++
>   board/nvidia/common/board.c                  |   12 ++
>   drivers/i2c/Makefile                         |    1 +
>   drivers/i2c/tegra_nvec.c                     |  294 ++++++++++++++++++++++++++
>   include/fdtdec.h                             |    1 +
>   lib/fdtdec.c                                 |    1 +
>   6 files changed, 439 insertions(+)
>   create mode 100644 arch/arm/include/asm/arch-tegra/tegra_nvec.h
>   create mode 100644 drivers/i2c/tegra_nvec.c
>
> diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec.h b/arch/arm/include/asm/arch-tegra/tegra_nvec.h
> new file mode 100644
> index 0000000..f1cec0d
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec.h
> @@ -0,0 +1,130 @@
> +/*
> + * (C) Copyright 2014
> + * Andrey Danin<danindrey@mail.ru>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _TEGRA_NVEC_H_
> +#define _TEGRA_NVEC_H_
> +
> +#define I2C_CNFG			0x00
> +#define I2C_CNFG_PACKET_MODE_EN		(1<<10)
> +#define I2C_CNFG_NEW_MASTER_SFM		(1<<11)
> +#define I2C_CNFG_DEBOUNCE_CNT_SHIFT	12
> +
> +#define I2C_SL_CNFG		0x20
> +#define I2C_SL_NEWSL		(1<<2)
> +#define I2C_SL_NACK		(1<<1)
> +#define I2C_SL_RESP		(1<<0)
> +#define I2C_SL_IRQ		(1<<3)
> +#define END_TRANS		(1<<4)
> +#define RCVD			(1<<2)
> +#define RNW			(1<<1)
> +
> +#define I2C_SL_RCVD		0x24
> +#define I2C_SL_STATUS		0x28
> +#define I2C_SL_ADDR1		0x2c
> +#define I2C_SL_ADDR2		0x30
> +#define I2C_SL_DELAY_COUNT	0x3c
> +
> +

please only one line, check globally.

[...]
> diff --git a/drivers/i2c/tegra_nvec.c b/drivers/i2c/tegra_nvec.c
> new file mode 100644
> index 0000000..b568988
> --- /dev/null
> +++ b/drivers/i2c/tegra_nvec.c
> @@ -0,0 +1,294 @@
> +/*
> + * (C) Copyright 2014
> + * Andrey Danin<danindrey@mail.ru>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include<common.h>
> +#include<fdtdec.h>
> +#include<i2c.h>
> +#include<asm/io.h>
> +#include<asm/gpio.h>
> +#include<asm/arch/clock.h>
> +#include<asm/arch/funcmux.h>
> +#include<asm/arch-tegra/tegra_nvec.h>
> +
> +#ifndef CONFIG_SYS_I2C_TEGRA_NVEC
> +#error "You should enable CONFIG_SYS_I2C_TEGRA_NVEC"
> +#endif
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct nvec_periph devices[NVEC_LAST_MSG];
> +
> +
> +struct nvec_t {
> +	int			i2c_bus;
> +	struct fdt_gpio_state	gpio;
> +} nvec_data;
> +
> +
> +/* nvec commands */
> +char noop[] = { NVEC_CNTL, CNTL_NOOP };
> +
> +void nvec_signal_request(void)
> +{
> +	gpio_set_value(nvec_data.gpio.gpio, 0);
> +}
> +
> +
> +void nvec_clear_request(void)
> +{
> +	gpio_set_value(nvec_data.gpio.gpio, 1);
> +}
> +
> +
> +int nvec_msg_is_event(const unsigned char *msg)
> +{
> +	return msg[0]>>  7;
> +}
> +
> +
> +int nvec_msg_event_type(const unsigned char *msg)
> +{
> +	return msg[0]&  0x0f;
> +}
> +
> +
> +/**
> + * Process incoming io message.
> + * If message is keyboard event then key code will
> + * be added to keys buffer.
> + *
> + * @param nvec	nvec state struct
> + */
> +void nvec_process_msg(struct nvec_t *nvec, struct i2c_transaction *trans)
> +{
> +	(void) nvec;
> +

no empty line needed.

> +	const unsigned char *msg = (const unsigned char *)&trans->rx_buf[1];
> +	int event_type;
> +
> +	if (!nvec_msg_is_event(msg))
> +		return;
> +
> +	event_type = nvec_msg_event_type(msg);
> +
> +	if (event_type<  NVEC_KEYBOARD || event_type>= NVEC_LAST_MSG)
> +		return;
> +
> +	if (devices[event_type].process_msg)
> +		devices[event_type].process_msg(msg);
> +}
> +
> +
> +/**
> + * Perform complete io operation (read or write).
> + * NOTE: function will wait NVEC_TIMEOUT_MIN (20ms)
> + * before status check to avoid nvec hang.
> + *
> + * @param nvec		nvec state struct
> + * @param wait_for_ec	if 1(NVEC_WAIT_FOR_EC) operation
> + *			timeout is NVEC_TIMEOUT_MAX (600ms),
> + *			otherwise function will return if io
> + *			is not ready.
> + *
> + * @return nvec_io_* code
> + */
> +int nvec_do_io(struct nvec_t *nvec)
> +{
> +	static unsigned int prev_timer;
> +	unsigned int poll_start_ms = get_timer(prev_timer);
> +	struct i2c_transaction trans;
> +	int res;
> +
> +	if (poll_start_ms>  30000) {
> +		if (prev_timer != 0)
> +			nvec_do_request(noop, sizeof(noop));
> +		prev_timer = get_timer(0);
> +	}
> +
> +	memset(&trans, 0, sizeof(trans));
> +	trans.start_timeout = 1;
> +	trans.timeout = 6000;
> +
> +	res = i2c_slave_io(&trans);
> +	if (res == 0) {
> +		nvec_process_msg(nvec,&trans);
> +		return 0;
> +	}
> +
> +	if (res != -1)
> +		debug("Error: i2c slave io failed with code %d\n", res);
> +
> +	return -1;
> +}
> +
> +/**
> + * Send request and read response. If write or read failed
> + * operation will be repeated NVEC_ATTEMPTS_MAX times.
> + *
> + * @param buf	request data
> + * @param size	request data size
> + * @return 0 if ok, -1 on error
> + */
> +int nvec_do_request(char *buf, int size)
> +{
> +	int res;
> +	struct i2c_transaction trans;
> +	int i;
> +
> +	nvec_signal_request();
> +
> +	/* Request */
> +	for (i = 0; i<  10; ++i) {
> +		memset(&trans, 0, sizeof(trans));
> +		trans.start_timeout = 600;
> +		trans.timeout = 6000;
> +
> +		trans.tx_buf[0] = (char)size;
> +		memcpy(&trans.tx_buf[1], buf, size);
> +		trans.tx_size = size + 1;
> +
> +		res = i2c_slave_io(&trans);
> +		if (res == 0) {
> +			if (trans.tx_pos == trans.tx_size)
> +				break;
> +
> +			debug("Request was not sent completely");
> +		} else if (res != -1) {
> +			debug("Unknown error while slave io");
> +		}
> +	}
> +	nvec_clear_request();
> +	if (res != 0) {
> +		error("nvec failed to perform request\n");
> +		return -1;
> +	}
> +
> +	/* Response */
> +	for (i = 0; i<  10; ++i) {
> +		memset(&trans, 0, sizeof(trans));
> +		trans.start_timeout = 600;
> +		trans.timeout = 6000;
> +
> +		res = i2c_slave_io(&trans);
> +		if (res == 0)
> +			break;
> +	}
> +	if (res != 0) {
> +		error("nvec failed to read response\n");
> +		return -1;
> +	}
> +
> +	/* TODO Parse response */

?

Is this not a complete driver?

> +
> +	return 0;
> +}
> +
> +
> +/**
> + * Decode the nvec information from the fdt.
> + *
> + * @param blob		fdt blob
> + * @param nvec		nvec device sturct
> + * @return 0 if ok, -ve on error

What is "-ve" ?

> + */
> +static int nvec_decode_config(const void *blob,
> +			      struct nvec_t *nvec)
> +{
> +	int node, parent;
> +	int i2c_bus;
> +
> +	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_NVEC);
> +	if (node<  0) {
> +		error("Cannot find NVEC node in fdt\n");
> +		return node;
> +	}
> +
> +	parent = fdt_parent_offset(blob, node);
> +	if (parent<  0) {
> +		debug("%s: Cannot find node parent\n", __func__);
> +		return -1;
> +	}
> +
> +	i2c_bus = i2c_get_bus_num_fdt(parent);
> +	if (i2c_bus<  0)
> +		return -1;
> +	nvec->i2c_bus = i2c_bus;
> +
> +	if (fdtdec_decode_gpio(blob, node, "request-gpios",
> +			&nvec->gpio)) {
> +		error("No NVEC request gpio\n");
> +		return -1;
> +	}
> +
> +	debug("NVEC: i2c:%d, gpio:%s(%u)\n",
> +	      nvec->i2c_bus, nvec->gpio.name, nvec->gpio.gpio);
> +	return 0;
> +}
> +
> +
> +int board_nvec_init(void)
> +{
> +	int res = 0;
> +	int i;
> +
> +	if (nvec_decode_config(gd->fdt_blob,&nvec_data)) {
> +		error("Can't parse NVEC node in device tree\n");
> +		return -1;
> +	}
> +
> +	debug("NVEC initialization...\n");
> +
> +	res = gpio_request(nvec_data.gpio.gpio, NULL);
> +	if (res != 0)
> +		error("NVEC: err, gpio_request\n");
> +	res = gpio_direction_output(nvec_data.gpio.gpio, 1);
> +	if (res != 0)
> +		error("NVEC: err, gpio_direction\n");
> +	res = gpio_set_value(nvec_data.gpio.gpio, 1);
> +	if (res != 0)
> +		error("NVEC: err, gpio_set_value\n");
> +	udelay(100);
> +
> +	i2c_set_bus_num(nvec_data.i2c_bus);
> +
> +	for (i = NVEC_KEYBOARD; i<  NVEC_LAST_MSG; ++i)
> +		if (devices[i].start) {
> +			debug("Starting device %d(0x%x)\n", i, i);
> +			devices[i].start();
> +		}
> +
> +	return 1;

Why "return 1"?

> +}
> +
> +
> +int nvec_read_events(void)
> +{
> +	int res;
> +	int cnt = 0;
> +
> +	while (++cnt<= 8) {
> +		res = nvec_do_io(&nvec_data);
> +		if (res)
> +			break;
> +
> +		/* TODO Process nvec communication errors */

Again a "TODO" ?

> +	}
> +
> +	return cnt;
> +}
> +
> +
> +int nvec_register_periph(int msg_type, struct nvec_periph *periph)
> +{
> +	if (devices[msg_type].start || devices[msg_type].process_msg) {
> +		error("Device for msg %d already registered\n", msg_type);
> +		return -1;
> +	}
> +
> +	devices[msg_type] = *periph;
> +	return 0;
> +}
> diff --git a/include/fdtdec.h b/include/fdtdec.h
> index 19bab79..7b84335 100644
> --- a/include/fdtdec.h
> +++ b/include/fdtdec.h
> @@ -64,6 +64,7 @@ enum fdt_compat_id {
>   	COMPAT_NVIDIA_TEGRA20_SDMMC,	/* Tegra20 SDMMC controller */
>   	COMPAT_NVIDIA_TEGRA20_SFLASH,	/* Tegra 2 SPI flash controller */
>   	COMPAT_NVIDIA_TEGRA20_SLINK,	/* Tegra 2 SPI SLINK controller */
> +	COMPAT_NVIDIA_TEGRA20_NVEC,	/* Tegra 2 EC controller */
>   	COMPAT_NVIDIA_TEGRA114_SPI,	/* Tegra 114 SPI controller */
>   	COMPAT_SMSC_LAN9215,		/* SMSC 10/100 Ethernet LAN9215 */
>   	COMPAT_SAMSUNG_EXYNOS5_SROMC,	/* Exynos5 SROMC */
> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
> index 1fecab3..82df701 100644
> --- a/lib/fdtdec.c
> +++ b/lib/fdtdec.c
> @@ -37,6 +37,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
>   	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
>   	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
>   	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
> +	COMPAT(NVIDIA_TEGRA20_NVEC, "nvidia,tegra20-nvec"),
>   	COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
>   	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
>   	COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),

bye,
Heiko
Andrey Danin April 29, 2014, 7:15 a.m. UTC | #2
On 29.04.2014 9:43, Heiko Schocher wrote:
> Hello Andrey,
>
Hello Heiko.

First of all, thank you for the review!

> Am 27.04.2014 03:14, schrieb Andrey Danin:
>> Signed-off-by: Andrey Danin<danindrey@mail.ru>
>> CC: Stephen Warren<swarren@nvidia.com>
>> CC: Marc Dietrich<marvin24@gmx.de>
>> CC: Julian Andres Klode<jak@jak-linux.org>
>> CC: ac100@lists.launchpad.net
>> ---
>>   Changes for v2:
>>     - NVEC driver was reworked to use tegra-i2c
>>
>>   arch/arm/include/asm/arch-tegra/tegra_nvec.h |  130 ++++++++++++
>>   board/nvidia/common/board.c                  |   12 ++
>>   drivers/i2c/Makefile                         |    1 +
>>   drivers/i2c/tegra_nvec.c                     |  294
>> ++++++++++++++++++++++++++
>>   include/fdtdec.h                             |    1 +
>>   lib/fdtdec.c                                 |    1 +
>>   6 files changed, 439 insertions(+)
>>   create mode 100644 arch/arm/include/asm/arch-tegra/tegra_nvec.h
>>   create mode 100644 drivers/i2c/tegra_nvec.c
>>
>> diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec.h
>> b/arch/arm/include/asm/arch-tegra/tegra_nvec.h
>> new file mode 100644
>> index 0000000..f1cec0d
>> --- /dev/null
>> +++ b/arch/arm/include/asm/arch-tegra/tegra_nvec.h
>> @@ -0,0 +1,130 @@
>> +/*
>> + * (C) Copyright 2014
>> + * Andrey Danin<danindrey@mail.ru>
>> + *
>> + * SPDX-License-Identifier:    GPL-2.0+
>> + */
>> +
>> +#ifndef _TEGRA_NVEC_H_
>> +#define _TEGRA_NVEC_H_
>> +
>> +#define I2C_CNFG            0x00
>> +#define I2C_CNFG_PACKET_MODE_EN        (1<<10)
>> +#define I2C_CNFG_NEW_MASTER_SFM        (1<<11)
>> +#define I2C_CNFG_DEBOUNCE_CNT_SHIFT    12
>> +
>> +#define I2C_SL_CNFG        0x20
>> +#define I2C_SL_NEWSL        (1<<2)
>> +#define I2C_SL_NACK        (1<<1)
>> +#define I2C_SL_RESP        (1<<0)
>> +#define I2C_SL_IRQ        (1<<3)
>> +#define END_TRANS        (1<<4)
>> +#define RCVD            (1<<2)
>> +#define RNW            (1<<1)
>> +
>> +#define I2C_SL_RCVD        0x24
>> +#define I2C_SL_STATUS        0x28
>> +#define I2C_SL_ADDR1        0x2c
>> +#define I2C_SL_ADDR2        0x30
>> +#define I2C_SL_DELAY_COUNT    0x3c
>> +
>> +
>
> please only one line, check globally.
>
I will. Thanks for pointing.

> [...]
>> diff --git a/drivers/i2c/tegra_nvec.c b/drivers/i2c/tegra_nvec.c
>> new file mode 100644
>> index 0000000..b568988
>> --- /dev/null
>> +++ b/drivers/i2c/tegra_nvec.c
>> @@ -0,0 +1,294 @@
>> +/*
>> + * (C) Copyright 2014
>> + * Andrey Danin<danindrey@mail.ru>
>> + *
>> + * SPDX-License-Identifier:    GPL-2.0+
>> + */
>> +
>> +#include<common.h>
>> +#include<fdtdec.h>
>> +#include<i2c.h>
>> +#include<asm/io.h>
>> +#include<asm/gpio.h>
>> +#include<asm/arch/clock.h>
>> +#include<asm/arch/funcmux.h>
>> +#include<asm/arch-tegra/tegra_nvec.h>
>> +
>> +#ifndef CONFIG_SYS_I2C_TEGRA_NVEC
>> +#error "You should enable CONFIG_SYS_I2C_TEGRA_NVEC"
>> +#endif
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +struct nvec_periph devices[NVEC_LAST_MSG];
>> +
>> +
>> +struct nvec_t {
>> +    int            i2c_bus;
>> +    struct fdt_gpio_state    gpio;
>> +} nvec_data;
>> +
>> +
>> +/* nvec commands */
>> +char noop[] = { NVEC_CNTL, CNTL_NOOP };
>> +
>> +void nvec_signal_request(void)
>> +{
>> +    gpio_set_value(nvec_data.gpio.gpio, 0);
>> +}
>> +
>> +
>> +void nvec_clear_request(void)
>> +{
>> +    gpio_set_value(nvec_data.gpio.gpio, 1);
>> +}
>> +
>> +
>> +int nvec_msg_is_event(const unsigned char *msg)
>> +{
>> +    return msg[0]>>  7;
>> +}
>> +
>> +
>> +int nvec_msg_event_type(const unsigned char *msg)
>> +{
>> +    return msg[0]&  0x0f;
>> +}
>> +
>> +
>> +/**
>> + * Process incoming io message.
>> + * If message is keyboard event then key code will
>> + * be added to keys buffer.
>> + *
>> + * @param nvec    nvec state struct
>> + */
>> +void nvec_process_msg(struct nvec_t *nvec, struct i2c_transaction
>> *trans)
>> +{
>> +    (void) nvec;
>> +
>
> no empty line needed.
>
>> +    const unsigned char *msg = (const unsigned char *)&trans->rx_buf[1];
>> +    int event_type;
>> +
>> +    if (!nvec_msg_is_event(msg))
>> +        return;
>> +
>> +    event_type = nvec_msg_event_type(msg);
>> +
>> +    if (event_type<  NVEC_KEYBOARD || event_type>= NVEC_LAST_MSG)
>> +        return;
>> +
>> +    if (devices[event_type].process_msg)
>> +        devices[event_type].process_msg(msg);
>> +}
>> +
>> +
>> +/**
>> + * Perform complete io operation (read or write).
>> + * NOTE: function will wait NVEC_TIMEOUT_MIN (20ms)
>> + * before status check to avoid nvec hang.
>> + *
>> + * @param nvec        nvec state struct
>> + * @param wait_for_ec    if 1(NVEC_WAIT_FOR_EC) operation
>> + *            timeout is NVEC_TIMEOUT_MAX (600ms),
>> + *            otherwise function will return if io
>> + *            is not ready.
>> + *
>> + * @return nvec_io_* code
>> + */
>> +int nvec_do_io(struct nvec_t *nvec)
>> +{
>> +    static unsigned int prev_timer;
>> +    unsigned int poll_start_ms = get_timer(prev_timer);
>> +    struct i2c_transaction trans;
>> +    int res;
>> +
>> +    if (poll_start_ms>  30000) {
>> +        if (prev_timer != 0)
>> +            nvec_do_request(noop, sizeof(noop));
>> +        prev_timer = get_timer(0);
>> +    }
>> +
>> +    memset(&trans, 0, sizeof(trans));
>> +    trans.start_timeout = 1;
>> +    trans.timeout = 6000;
>> +
>> +    res = i2c_slave_io(&trans);
>> +    if (res == 0) {
>> +        nvec_process_msg(nvec,&trans);
>> +        return 0;
>> +    }
>> +
>> +    if (res != -1)
>> +        debug("Error: i2c slave io failed with code %d\n", res);
>> +
>> +    return -1;
>> +}
>> +
>> +/**
>> + * Send request and read response. If write or read failed
>> + * operation will be repeated NVEC_ATTEMPTS_MAX times.
>> + *
>> + * @param buf    request data
>> + * @param size    request data size
>> + * @return 0 if ok, -1 on error
>> + */
>> +int nvec_do_request(char *buf, int size)
>> +{
>> +    int res;
>> +    struct i2c_transaction trans;
>> +    int i;
>> +
>> +    nvec_signal_request();
>> +
>> +    /* Request */
>> +    for (i = 0; i<  10; ++i) {
>> +        memset(&trans, 0, sizeof(trans));
>> +        trans.start_timeout = 600;
>> +        trans.timeout = 6000;
>> +
>> +        trans.tx_buf[0] = (char)size;
>> +        memcpy(&trans.tx_buf[1], buf, size);
>> +        trans.tx_size = size + 1;
>> +
>> +        res = i2c_slave_io(&trans);
>> +        if (res == 0) {
>> +            if (trans.tx_pos == trans.tx_size)
>> +                break;
>> +
>> +            debug("Request was not sent completely");
>> +        } else if (res != -1) {
>> +            debug("Unknown error while slave io");
>> +        }
>> +    }
>> +    nvec_clear_request();
>> +    if (res != 0) {
>> +        error("nvec failed to perform request\n");
>> +        return -1;
>> +    }
>> +
>> +    /* Response */
>> +    for (i = 0; i<  10; ++i) {
>> +        memset(&trans, 0, sizeof(trans));
>> +        trans.start_timeout = 600;
>> +        trans.timeout = 6000;
>> +
>> +        res = i2c_slave_io(&trans);
>> +        if (res == 0)
>> +            break;
>> +    }
>> +    if (res != 0) {
>> +        error("nvec failed to read response\n");
>> +        return -1;
>> +    }
>> +
>> +    /* TODO Parse response */
>
> ?
>
> Is this not a complete driver?
>
The driver is complete. This part is not mandatory because request and 
response are processed synchronously. I will write a proper comment here.

>> +
>> +    return 0;
>> +}
>> +
>> +
>> +/**
>> + * Decode the nvec information from the fdt.
>> + *
>> + * @param blob        fdt blob
>> + * @param nvec        nvec device sturct
>> + * @return 0 if ok, -ve on error
>
> What is "-ve" ?
>
It means -error_code.
I will rework return codes, comments, style issues according to all your 
remarks.

>> + */
>> +static int nvec_decode_config(const void *blob,
>> +                  struct nvec_t *nvec)
>> +{
>> +    int node, parent;
>> +    int i2c_bus;
>> +
>> +    node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_NVEC);
>> +    if (node<  0) {
>> +        error("Cannot find NVEC node in fdt\n");
>> +        return node;
>> +    }
>> +
>> +    parent = fdt_parent_offset(blob, node);
>> +    if (parent<  0) {
>> +        debug("%s: Cannot find node parent\n", __func__);
>> +        return -1;
>> +    }
>> +
>> +    i2c_bus = i2c_get_bus_num_fdt(parent);
>> +    if (i2c_bus<  0)
>> +        return -1;
>> +    nvec->i2c_bus = i2c_bus;
>> +
>> +    if (fdtdec_decode_gpio(blob, node, "request-gpios",
>> +            &nvec->gpio)) {
>> +        error("No NVEC request gpio\n");
>> +        return -1;
>> +    }
>> +
>> +    debug("NVEC: i2c:%d, gpio:%s(%u)\n",
>> +          nvec->i2c_bus, nvec->gpio.name, nvec->gpio.gpio);
>> +    return 0;
>> +}
>> +
>> +
>> +int board_nvec_init(void)
>> +{
>> +    int res = 0;
>> +    int i;
>> +
>> +    if (nvec_decode_config(gd->fdt_blob,&nvec_data)) {
>> +        error("Can't parse NVEC node in device tree\n");
>> +        return -1;
>> +    }
>> +
>> +    debug("NVEC initialization...\n");
>> +
>> +    res = gpio_request(nvec_data.gpio.gpio, NULL);
>> +    if (res != 0)
>> +        error("NVEC: err, gpio_request\n");
>> +    res = gpio_direction_output(nvec_data.gpio.gpio, 1);
>> +    if (res != 0)
>> +        error("NVEC: err, gpio_direction\n");
>> +    res = gpio_set_value(nvec_data.gpio.gpio, 1);
>> +    if (res != 0)
>> +        error("NVEC: err, gpio_set_value\n");
>> +    udelay(100);
>> +
>> +    i2c_set_bus_num(nvec_data.i2c_bus);
>> +
>> +    for (i = NVEC_KEYBOARD; i<  NVEC_LAST_MSG; ++i)
>> +        if (devices[i].start) {
>> +            debug("Starting device %d(0x%x)\n", i, i);
>> +            devices[i].start();
>> +        }
>> +
>> +    return 1;
>
> Why "return 1"?
>
>> +}
>> +
>> +
>> +int nvec_read_events(void)
>> +{
>> +    int res;
>> +    int cnt = 0;
>> +
>> +    while (++cnt<= 8) {
>> +        res = nvec_do_io(&nvec_data);
>> +        if (res)
>> +            break;
>> +
>> +        /* TODO Process nvec communication errors */
>
> Again a "TODO" ?
>
I will implement.

>> +    }
>> +
>> +    return cnt;
>> +}
>> +
>> +
>> +int nvec_register_periph(int msg_type, struct nvec_periph *periph)
>> +{
>> +    if (devices[msg_type].start || devices[msg_type].process_msg) {
>> +        error("Device for msg %d already registered\n", msg_type);
>> +        return -1;
>> +    }
>> +
>> +    devices[msg_type] = *periph;
>> +    return 0;
>> +}
>> diff --git a/include/fdtdec.h b/include/fdtdec.h
>> index 19bab79..7b84335 100644
>> --- a/include/fdtdec.h
>> +++ b/include/fdtdec.h
>> @@ -64,6 +64,7 @@ enum fdt_compat_id {
>>       COMPAT_NVIDIA_TEGRA20_SDMMC,    /* Tegra20 SDMMC controller */
>>       COMPAT_NVIDIA_TEGRA20_SFLASH,    /* Tegra 2 SPI flash controller */
>>       COMPAT_NVIDIA_TEGRA20_SLINK,    /* Tegra 2 SPI SLINK controller */
>> +    COMPAT_NVIDIA_TEGRA20_NVEC,    /* Tegra 2 EC controller */
>>       COMPAT_NVIDIA_TEGRA114_SPI,    /* Tegra 114 SPI controller */
>>       COMPAT_SMSC_LAN9215,        /* SMSC 10/100 Ethernet LAN9215 */
>>       COMPAT_SAMSUNG_EXYNOS5_SROMC,    /* Exynos5 SROMC */
>> diff --git a/lib/fdtdec.c b/lib/fdtdec.c
>> index 1fecab3..82df701 100644
>> --- a/lib/fdtdec.c
>> +++ b/lib/fdtdec.c
>> @@ -37,6 +37,7 @@ static const char * const compat_names[COMPAT_COUNT]
>> = {
>>       COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
>>       COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
>>       COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
>> +    COMPAT(NVIDIA_TEGRA20_NVEC, "nvidia,tegra20-nvec"),
>>       COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
>>       COMPAT(SMSC_LAN9215, "smsc,lan9215"),
>>       COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
>
> bye,
> Heiko

Thanks.
Heiko Schocher April 29, 2014, 8:07 a.m. UTC | #3
Hello Andrey,

Am 29.04.2014 09:15, schrieb Andrey Danin:
> On 29.04.2014 9:43, Heiko Schocher wrote:
>> Hello Andrey,
>>
> Hello Heiko.
>
> First of all, thank you for the review!

You are welcome.

>> Am 27.04.2014 03:14, schrieb Andrey Danin:
>>> Signed-off-by: Andrey Danin<danindrey@mail.ru>
>>> CC: Stephen Warren<swarren@nvidia.com>
>>> CC: Marc Dietrich<marvin24@gmx.de>
>>> CC: Julian Andres Klode<jak@jak-linux.org>
>>> CC: ac100@lists.launchpad.net
>>> ---
>>> Changes for v2:
>>> - NVEC driver was reworked to use tegra-i2c
>>>
>>> arch/arm/include/asm/arch-tegra/tegra_nvec.h | 130 ++++++++++++
>>> board/nvidia/common/board.c | 12 ++
>>> drivers/i2c/Makefile | 1 +
>>> drivers/i2c/tegra_nvec.c | 294
>>> ++++++++++++++++++++++++++
>>> include/fdtdec.h | 1 +
>>> lib/fdtdec.c | 1 +
>>> 6 files changed, 439 insertions(+)
>>> create mode 100644 arch/arm/include/asm/arch-tegra/tegra_nvec.h
>>> create mode 100644 drivers/i2c/tegra_nvec.c
[...]
>>> diff --git a/drivers/i2c/tegra_nvec.c b/drivers/i2c/tegra_nvec.c
>>> new file mode 100644
>>> index 0000000..b568988
>>> --- /dev/null
>>> +++ b/drivers/i2c/tegra_nvec.c
>>> @@ -0,0 +1,294 @@
[...]
>>> + /* TODO Parse response */
>>
>> ?
>>
>> Is this not a complete driver?
>>
> The driver is complete. This part is not mandatory because request and response are processed synchronously. I will write a proper comment here.

Ok, thanks!

>>> +
>>> + return 0;
>>> +}
>>> +
>>> +
>>> +/**
>>> + * Decode the nvec information from the fdt.
>>> + *
>>> + * @param blob fdt blob
>>> + * @param nvec nvec device sturct
>>> + * @return 0 if ok, -ve on error
>>
>> What is "-ve" ?
>>
> It means -error_code.
> I will rework return codes, comments, style issues according to all your remarks.

Thanks!

[...]
>>> +int nvec_read_events(void)
>>> +{
>>> + int res;
>>> + int cnt = 0;
>>> +
>>> + while (++cnt<= 8) {
>>> + res = nvec_do_io(&nvec_data);
>>> + if (res)
>>> + break;
>>> +
>>> + /* TODO Process nvec communication errors */
>>
>> Again a "TODO" ?
>>
> I will implement.

Sounds great, thanks!

[...]

bye,
Heiko
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-tegra/tegra_nvec.h b/arch/arm/include/asm/arch-tegra/tegra_nvec.h
new file mode 100644
index 0000000..f1cec0d
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra/tegra_nvec.h
@@ -0,0 +1,130 @@ 
+/*
+ * (C) Copyright 2014
+ * Andrey Danin <danindrey@mail.ru>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _TEGRA_NVEC_H_
+#define _TEGRA_NVEC_H_
+
+#define I2C_CNFG			0x00
+#define I2C_CNFG_PACKET_MODE_EN		(1<<10)
+#define I2C_CNFG_NEW_MASTER_SFM		(1<<11)
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT	12
+
+#define I2C_SL_CNFG		0x20
+#define I2C_SL_NEWSL		(1<<2)
+#define I2C_SL_NACK		(1<<1)
+#define I2C_SL_RESP		(1<<0)
+#define I2C_SL_IRQ		(1<<3)
+#define END_TRANS		(1<<4)
+#define RCVD			(1<<2)
+#define RNW			(1<<1)
+
+#define I2C_SL_RCVD		0x24
+#define I2C_SL_STATUS		0x28
+#define I2C_SL_ADDR1		0x2c
+#define I2C_SL_ADDR2		0x30
+#define I2C_SL_DELAY_COUNT	0x3c
+
+
+enum nvec_msg_type {
+	NVEC_KEYBOARD = 0,
+	NVEC_SYS = 1,
+	NVEC_BAT,
+	NVEC_GPIO,
+	NVEC_SLEEP,
+	NVEC_KBD,
+	NVEC_PS2,
+	NVEC_CNTL,
+	NVEC_OEM0 = 0x0d,
+	NVEC_KB_EVT = 0x80,
+	NVEC_PS2_EVT,
+	NVEC_LAST_MSG,
+};
+
+enum nvec_event_size {
+	NVEC_2BYTES,
+	NVEC_3BYTES,
+	NVEC_VAR_SIZE,
+};
+
+enum sys_subcmds {
+	SYS_GET_STATUS,
+	SYS_CNFG_EVENT_REPORTING,
+	SYS_ACK_STATUS,
+	SYS_CNFG_WAKE = 0xfd,
+};
+
+enum kbd_subcmds {
+	CNFG_WAKE = 3,
+	CNFG_WAKE_KEY_REPORTING,
+	SET_LEDS = 0xed,
+	ENABLE_KBD = 0xf4,
+	DISABLE_KBD,
+};
+
+enum cntl_subcmds {
+	CNTL_RESET_EC = 0x00,
+	CNTL_SELF_TEST = 0x01,
+	CNTL_NOOP = 0x02,
+	CNTL_GET_EC_SPEC_VER = 0x10,
+	CNTL_GET_FIRMWARE_VERSION = 0x15,
+};
+
+enum nvec_sleep_subcmds {
+	GLOBAL_EVENTS,
+	AP_PWR_DOWN,
+	AP_SUSPEND,
+};
+
+enum ps2_subcmds {
+	MOUSE_SEND_CMD = 0x01
+};
+
+#define MOUSE_RESET 0xff
+
+typedef int (*periph_start)(void);
+typedef int (*periph_process_msg)(const unsigned char *);
+
+struct nvec_periph {
+	periph_start		start;
+	periph_process_msg	process_msg;
+};
+
+
+int board_nvec_init(void);
+
+/**
+ * Read all available events.
+ *
+ * @return count of available events if ok, -1 on error
+ */
+int nvec_read_events(void);
+
+int nvec_msg_is_event(const unsigned char *msg);
+int nvec_msg_event_type(const unsigned char *msg);
+
+/**
+ * Register perepherial device driver.
+ *
+ * @param msg_type	type of messages that divece processes.
+ * @param periph	pointer to device description.
+ *
+ * @return 0 if ok, -1 on error
+ */
+int nvec_register_periph(int msg_type, struct nvec_periph *periph);
+
+/**
+ * Send request and read response. If write or read failed
+ * operation will be repeated NVEC_ATTEMPTS_MAX times.
+ *
+ * @param buf		request data
+ * @param size		request data size
+ * @return 0 if ok, -1 on error
+ */
+int nvec_do_request(char *buf, int size);
+
+
+#endif /* _TEGRA_NVEC_H_ */
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index 3b18e28..6d3055c 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -38,6 +38,9 @@ 
 #include <asm/arch-tegra/tegra_mmc.h>
 #include <asm/arch-tegra/mmc.h>
 #endif
+#ifdef CONFIG_SYS_I2C_TEGRA_NVEC
+#include <asm/arch-tegra/tegra_nvec.h>
+#endif
 #include <i2c.h>
 #include <spi.h>
 #include "emc.h"
@@ -194,10 +197,19 @@  int board_early_init_f(void)
 
 int board_late_init(void)
 {
+	__maybe_unused int err;
+
 #ifdef CONFIG_LCD
 	/* Make sure we finish initing the LCD */
 	tegra_lcd_check_next_stage(gd->fdt_blob, 1);
 #endif
+
+#ifdef CONFIG_SYS_I2C_TEGRA_NVEC
+	err = board_nvec_init();
+	if (err)
+		debug("NVEC controller init failed: %d\n", err);
+#endif
+
 	return 0;
 }
 
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index fa3a875..3041191 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -27,4 +27,5 @@  obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
+obj-$(CONFIG_SYS_I2C_TEGRA_NVEC) += tegra_nvec.o
 obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
diff --git a/drivers/i2c/tegra_nvec.c b/drivers/i2c/tegra_nvec.c
new file mode 100644
index 0000000..b568988
--- /dev/null
+++ b/drivers/i2c/tegra_nvec.c
@@ -0,0 +1,294 @@ 
+/*
+ * (C) Copyright 2014
+ * Andrey Danin <danindrey@mail.ru>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch-tegra/tegra_nvec.h>
+
+#ifndef CONFIG_SYS_I2C_TEGRA_NVEC
+#error "You should enable CONFIG_SYS_I2C_TEGRA_NVEC"
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct nvec_periph devices[NVEC_LAST_MSG];
+
+
+struct nvec_t {
+	int			i2c_bus;
+	struct fdt_gpio_state	gpio;
+} nvec_data;
+
+
+/* nvec commands */
+char noop[] = { NVEC_CNTL, CNTL_NOOP };
+
+void nvec_signal_request(void)
+{
+	gpio_set_value(nvec_data.gpio.gpio, 0);
+}
+
+
+void nvec_clear_request(void)
+{
+	gpio_set_value(nvec_data.gpio.gpio, 1);
+}
+
+
+int nvec_msg_is_event(const unsigned char *msg)
+{
+	return msg[0] >> 7;
+}
+
+
+int nvec_msg_event_type(const unsigned char *msg)
+{
+	return msg[0] & 0x0f;
+}
+
+
+/**
+ * Process incoming io message.
+ * If message is keyboard event then key code will
+ * be added to keys buffer.
+ *
+ * @param nvec	nvec state struct
+ */
+void nvec_process_msg(struct nvec_t *nvec, struct i2c_transaction *trans)
+{
+	(void) nvec;
+
+	const unsigned char *msg = (const unsigned char *)&trans->rx_buf[1];
+	int event_type;
+
+	if (!nvec_msg_is_event(msg))
+		return;
+
+	event_type = nvec_msg_event_type(msg);
+
+	if (event_type < NVEC_KEYBOARD || event_type >= NVEC_LAST_MSG)
+		return;
+
+	if (devices[event_type].process_msg)
+		devices[event_type].process_msg(msg);
+}
+
+
+/**
+ * Perform complete io operation (read or write).
+ * NOTE: function will wait NVEC_TIMEOUT_MIN (20ms)
+ * before status check to avoid nvec hang.
+ *
+ * @param nvec		nvec state struct
+ * @param wait_for_ec	if 1(NVEC_WAIT_FOR_EC) operation
+ *			timeout is NVEC_TIMEOUT_MAX (600ms),
+ *			otherwise function will return if io
+ *			is not ready.
+ *
+ * @return nvec_io_* code
+ */
+int nvec_do_io(struct nvec_t *nvec)
+{
+	static unsigned int prev_timer;
+	unsigned int poll_start_ms = get_timer(prev_timer);
+	struct i2c_transaction trans;
+	int res;
+
+	if (poll_start_ms > 30000) {
+		if (prev_timer != 0)
+			nvec_do_request(noop, sizeof(noop));
+		prev_timer = get_timer(0);
+	}
+
+	memset(&trans, 0, sizeof(trans));
+	trans.start_timeout = 1;
+	trans.timeout = 6000;
+
+	res = i2c_slave_io(&trans);
+	if (res == 0) {
+		nvec_process_msg(nvec, &trans);
+		return 0;
+	}
+
+	if (res != -1)
+		debug("Error: i2c slave io failed with code %d\n", res);
+
+	return -1;
+}
+
+/**
+ * Send request and read response. If write or read failed
+ * operation will be repeated NVEC_ATTEMPTS_MAX times.
+ *
+ * @param buf	request data
+ * @param size	request data size
+ * @return 0 if ok, -1 on error
+ */
+int nvec_do_request(char *buf, int size)
+{
+	int res;
+	struct i2c_transaction trans;
+	int i;
+
+	nvec_signal_request();
+
+	/* Request */
+	for (i = 0; i < 10; ++i) {
+		memset(&trans, 0, sizeof(trans));
+		trans.start_timeout = 600;
+		trans.timeout = 6000;
+
+		trans.tx_buf[0] = (char)size;
+		memcpy(&trans.tx_buf[1], buf, size);
+		trans.tx_size = size + 1;
+
+		res = i2c_slave_io(&trans);
+		if (res == 0) {
+			if (trans.tx_pos == trans.tx_size)
+				break;
+
+			debug("Request was not sent completely");
+		} else if (res != -1) {
+			debug("Unknown error while slave io");
+		}
+	}
+	nvec_clear_request();
+	if (res != 0) {
+		error("nvec failed to perform request\n");
+		return -1;
+	}
+
+	/* Response */
+	for (i = 0; i < 10; ++i) {
+		memset(&trans, 0, sizeof(trans));
+		trans.start_timeout = 600;
+		trans.timeout = 6000;
+
+		res = i2c_slave_io(&trans);
+		if (res == 0)
+			break;
+	}
+	if (res != 0) {
+		error("nvec failed to read response\n");
+		return -1;
+	}
+
+	/* TODO Parse response */
+
+	return 0;
+}
+
+
+/**
+ * Decode the nvec information from the fdt.
+ *
+ * @param blob		fdt blob
+ * @param nvec		nvec device sturct
+ * @return 0 if ok, -ve on error
+ */
+static int nvec_decode_config(const void *blob,
+			      struct nvec_t *nvec)
+{
+	int node, parent;
+	int i2c_bus;
+
+	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_NVEC);
+	if (node < 0) {
+		error("Cannot find NVEC node in fdt\n");
+		return node;
+	}
+
+	parent = fdt_parent_offset(blob, node);
+	if (parent < 0) {
+		debug("%s: Cannot find node parent\n", __func__);
+		return -1;
+	}
+
+	i2c_bus = i2c_get_bus_num_fdt(parent);
+	if (i2c_bus < 0)
+		return -1;
+	nvec->i2c_bus = i2c_bus;
+
+	if (fdtdec_decode_gpio(blob, node, "request-gpios",
+			       &nvec->gpio)) {
+		error("No NVEC request gpio\n");
+		return -1;
+	}
+
+	debug("NVEC: i2c:%d, gpio:%s(%u)\n",
+	      nvec->i2c_bus, nvec->gpio.name, nvec->gpio.gpio);
+	return 0;
+}
+
+
+int board_nvec_init(void)
+{
+	int res = 0;
+	int i;
+
+	if (nvec_decode_config(gd->fdt_blob, &nvec_data)) {
+		error("Can't parse NVEC node in device tree\n");
+		return -1;
+	}
+
+	debug("NVEC initialization...\n");
+
+	res = gpio_request(nvec_data.gpio.gpio, NULL);
+	if (res != 0)
+		error("NVEC: err, gpio_request\n");
+	res = gpio_direction_output(nvec_data.gpio.gpio, 1);
+	if (res != 0)
+		error("NVEC: err, gpio_direction\n");
+	res = gpio_set_value(nvec_data.gpio.gpio, 1);
+	if (res != 0)
+		error("NVEC: err, gpio_set_value\n");
+	udelay(100);
+
+	i2c_set_bus_num(nvec_data.i2c_bus);
+
+	for (i = NVEC_KEYBOARD; i < NVEC_LAST_MSG; ++i)
+		if (devices[i].start) {
+			debug("Starting device %d(0x%x)\n", i, i);
+			devices[i].start();
+		}
+
+	return 1;
+}
+
+
+int nvec_read_events(void)
+{
+	int res;
+	int cnt = 0;
+
+	while (++cnt <= 8) {
+		res = nvec_do_io(&nvec_data);
+		if (res)
+			break;
+
+		/* TODO Process nvec communication errors */
+	}
+
+	return cnt;
+}
+
+
+int nvec_register_periph(int msg_type, struct nvec_periph *periph)
+{
+	if (devices[msg_type].start || devices[msg_type].process_msg) {
+		error("Device for msg %d already registered\n", msg_type);
+		return -1;
+	}
+
+	devices[msg_type] = *periph;
+	return 0;
+}
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 19bab79..7b84335 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -64,6 +64,7 @@  enum fdt_compat_id {
 	COMPAT_NVIDIA_TEGRA20_SDMMC,	/* Tegra20 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA20_SFLASH,	/* Tegra 2 SPI flash controller */
 	COMPAT_NVIDIA_TEGRA20_SLINK,	/* Tegra 2 SPI SLINK controller */
+	COMPAT_NVIDIA_TEGRA20_NVEC,	/* Tegra 2 EC controller */
 	COMPAT_NVIDIA_TEGRA114_SPI,	/* Tegra 114 SPI controller */
 	COMPAT_SMSC_LAN9215,		/* SMSC 10/100 Ethernet LAN9215 */
 	COMPAT_SAMSUNG_EXYNOS5_SROMC,	/* Exynos5 SROMC */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 1fecab3..82df701 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -37,6 +37,7 @@  static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
 	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
 	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
+	COMPAT(NVIDIA_TEGRA20_NVEC, "nvidia,tegra20-nvec"),
 	COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
 	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
 	COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),