Thread Previous • Date Previous • Date Next • Thread Next |
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@xxxxxxx> CC: Stephen Warren<swarren@xxxxxxxxxx> CC: Marc Dietrich<marvin24@xxxxxx> CC: Julian Andres Klode<jak@xxxxxxxxxxxxx> CC: ac100@xxxxxxxxxxxxxxxxxxx --- 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@xxxxxxx> + * + * 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.
The driver is complete. This part is not mandatory because request and response are processed synchronously. I will write a proper comment here.[...]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@xxxxxxx> + * + * 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 errorWhat 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.
Thread Previous • Date Previous • Date Next • Thread Next |