diff --git a/drivers/eeprom/CMakeLists.txt b/drivers/eeprom/CMakeLists.txt index eaac83a4f6a..870fdc901f1 100644 --- a/drivers/eeprom/CMakeLists.txt +++ b/drivers/eeprom/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_EEPROM_LPC11U6X eeprom_lpc11u6x.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_STM32 eeprom_stm32.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_SIMULATOR eeprom_simulator.c) zephyr_library_sources_ifdef(CONFIG_EEPROM_EMULATOR eeprom_emulator.c) +zephyr_library_sources_ifdef(CONFIG_EEPROM_TMP116 eeprom_tmp116.c) diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig index c6d726aa632..e31f8fd67dc 100644 --- a/drivers/eeprom/Kconfig +++ b/drivers/eeprom/Kconfig @@ -58,6 +58,7 @@ config EEPROM_AT25 source "drivers/eeprom/Kconfig.lpc11u6x" source "drivers/eeprom/Kconfig.stm32" source "drivers/eeprom/Kconfig.eeprom_emu" +source "drivers/eeprom/Kconfig.tmp116" config EEPROM_SIMULATOR bool "Simulated EEPROM driver" diff --git a/drivers/eeprom/Kconfig.tmp116 b/drivers/eeprom/Kconfig.tmp116 new file mode 100644 index 00000000000..231e2da0296 --- /dev/null +++ b/drivers/eeprom/Kconfig.tmp116 @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Innoseis B.V. +# SPDX-License-Identifier: Apache-2.0 + +config EEPROM_TMP116 + bool "TMP116 EEPROM driver" + depends on TMP116 + default y + help + Enable support for the on-chip EEPROM found on + Texas instrument TMP116 temperature sensor diff --git a/drivers/eeprom/eeprom_tmp116.c b/drivers/eeprom/eeprom_tmp116.c new file mode 100644 index 00000000000..0180ca0b1b5 --- /dev/null +++ b/drivers/eeprom/eeprom_tmp116.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Innoseis B.V + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define DT_DRV_COMPAT ti_tmp116_eeprom + +struct eeprom_tmp116_config { + const struct device *parent; +}; + +BUILD_ASSERT(CONFIG_EEPROM_INIT_PRIORITY > + CONFIG_SENSOR_INIT_PRIORITY, + "TMP116 eeprom driver must be initialized after TMP116 sensor " + "driver"); + +static size_t eeprom_tmp116_size(const struct device *dev) +{ + return EEPROM_TMP116_SIZE; +} + +static int eeprom_tmp116_write(const struct device *dev, off_t offset, + const void *data, size_t len) +{ + const struct eeprom_tmp116_config *config = dev->config; + + return tmp116_eeprom_write(config->parent, offset, data, len); +} + +static int eeprom_tmp116_read(const struct device *dev, off_t offset, void *data, + size_t len) +{ + const struct eeprom_tmp116_config *config = dev->config; + + return tmp116_eeprom_read(config->parent, offset, data, len); +} + +static int eeprom_tmp116_init(const struct device *dev) +{ + const struct eeprom_tmp116_config *config = dev->config; + + if (!device_is_ready(config->parent)) { + return -ENODEV; + } + + return 0; +} + +static const struct eeprom_driver_api eeprom_tmp116_api = { + .read = eeprom_tmp116_read, + .write = eeprom_tmp116_write, + .size = eeprom_tmp116_size, +}; + +#define DEFINE_TMP116(_num) \ + static const struct eeprom_tmp116_config eeprom_tmp116_config##_num = { \ + .parent = DEVICE_DT_GET(DT_INST_BUS(_num)) \ + }; \ + DEVICE_DT_INST_DEFINE(_num, eeprom_tmp116_init, NULL, \ + NULL, &eeprom_tmp116_config##_num, POST_KERNEL, \ + CONFIG_EEPROM_INIT_PRIORITY, &eeprom_tmp116_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMP116); diff --git a/drivers/sensor/tmp116/tmp116.c b/drivers/sensor/tmp116/tmp116.c index b7e057113fe..bf1d0564374 100644 --- a/drivers/sensor/tmp116/tmp116.c +++ b/drivers/sensor/tmp116/tmp116.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,10 @@ #include "tmp116.h" +#define EEPROM_SIZE_REG sizeof(uint16_t) +#define EEPROM_TMP117_RESERVED (2 * sizeof(uint16_t)) +#define EEPROM_MIN_BUSY_MS 7 + LOG_MODULE_REGISTER(TMP116, CONFIG_SENSOR_LOG_LEVEL); static int tmp116_reg_read(const struct device *dev, uint8_t reg, @@ -43,6 +48,94 @@ static int tmp116_reg_write(const struct device *dev, uint8_t reg, return i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf)); } +static bool check_eeprom_bounds(const struct device *dev, off_t offset, + size_t len) +{ + struct tmp116_data *drv_data = dev->data; + + if ((offset + len) > EEPROM_TMP116_SIZE || + offset % EEPROM_SIZE_REG != 0 || + len % EEPROM_SIZE_REG != 0) { + return false; + } + + /* TMP117 uses EEPROM[2] as temperature offset register */ + if (drv_data->id == TMP117_DEVICE_ID && + offset <= EEPROM_TMP117_RESERVED && + (offset + len) > EEPROM_TMP117_RESERVED) { + return false; + } + + return true; +} + +int tmp116_eeprom_write(const struct device *dev, off_t offset, + const void *data, size_t len) +{ + uint8_t reg; + const uint16_t *src = data; + int res; + + if (!check_eeprom_bounds(dev, offset, len)) { + return -EINVAL; + } + + res = tmp116_reg_write(dev, TMP116_REG_EEPROM_UL, TMP116_EEPROM_UL_UNLOCK); + if (res) { + return res; + } + + for (reg = (offset / 2); reg < offset / 2 + len / 2; reg++) { + uint16_t val = *src; + + res = tmp116_reg_write(dev, reg + TMP116_REG_EEPROM1, val); + if (res != 0) { + break; + } + + k_sleep(K_MSEC(EEPROM_MIN_BUSY_MS)); + + do { + res = tmp116_reg_read(dev, TMP116_REG_EEPROM_UL, &val); + if (res != 0) { + break; + } + } while (val & TMP116_EEPROM_UL_BUSY); + src++; + + if (res != 0) { + break; + } + } + + res = tmp116_reg_write(dev, TMP116_REG_EEPROM_UL, 0); + + return res; +} + +int tmp116_eeprom_read(const struct device *dev, off_t offset, void *data, + size_t len) +{ + uint8_t reg; + uint16_t *dst = data; + int res = 0; + + if (!check_eeprom_bounds(dev, offset, len)) { + return -EINVAL; + } + + for (reg = (offset / 2); reg < offset / 2 + len / 2; reg++) { + res = tmp116_reg_read(dev, reg + TMP116_REG_EEPROM1, dst); + if (res != 0) { + break; + } + dst++; + } + + return res; +} + + /** * @brief Check the Device ID * diff --git a/drivers/sensor/tmp116/tmp116.h b/drivers/sensor/tmp116/tmp116.h index 3deadde9839..97263af5844 100644 --- a/drivers/sensor/tmp116/tmp116.h +++ b/drivers/sensor/tmp116/tmp116.h @@ -25,7 +25,9 @@ #define TMP116_DEVICE_ID 0x1116 #define TMP117_DEVICE_ID 0x0117 -#define TMP116_CFGR_DATA_READY BIT(13) +#define TMP116_CFGR_DATA_READY BIT(13) +#define TMP116_EEPROM_UL_UNLOCK BIT(15) +#define TMP116_EEPROM_UL_BUSY BIT(14) struct tmp116_data { uint16_t sample; diff --git a/dts/bindings/mtd/ti,tmp116-eeprom.yaml b/dts/bindings/mtd/ti,tmp116-eeprom.yaml new file mode 100644 index 00000000000..4c4188b0c70 --- /dev/null +++ b/dts/bindings/mtd/ti,tmp116-eeprom.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2020 Innoseis B.V +# SPDX-License-Identifier: Apache-2.0 + +description: TI TMP116 EEPROM controller binding + +compatible: "ti,tmp116-eeprom" + +include: eeprom-base.yaml + +on-bus: tmp116 diff --git a/dts/bindings/sensor/ti,tmp116.yaml b/dts/bindings/sensor/ti,tmp116.yaml index ad2c0acb1c6..0753b92efa4 100644 --- a/dts/bindings/sensor/ti,tmp116.yaml +++ b/dts/bindings/sensor/ti,tmp116.yaml @@ -5,4 +5,6 @@ description: Texas Instruments TMP116 temperature sensor compatible: "ti,tmp116" +bus: tmp116 + include: i2c-device.yaml diff --git a/include/drivers/sensor/tmp116.h b/include/drivers/sensor/tmp116.h new file mode 100644 index 00000000000..b21fe76b4e4 --- /dev/null +++ b/include/drivers/sensor/tmp116.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 Innoseis B.V + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_TMP116_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_TMP116_H_ + +#include +#include + +#define EEPROM_TMP116_SIZE (4 * sizeof(uint16_t)) + +int tmp116_eeprom_read(const struct device *dev, off_t offset, void *data, + size_t len); + +int tmp116_eeprom_write(const struct device *dev, off_t offset, + const void *data, size_t len); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_TMP116_H_ */