From 84b0492fbd87e6fd00387fe91c28d3e6ab76d371 Mon Sep 17 00:00:00 2001 From: Stepan Pressl Date: Thu, 9 Oct 2025 19:21:18 +0200 Subject: [PATCH] drivers/1wire/1wire_ds2xxx.h: add the driver for DS2XXX eeproms. Supports these Maxim/Analog Devices eeproms with a scratchpad: DS2430,2431,2432,2433,28E04,28E07,28EC20. For each type of an eeprom, you create a new driver. Other than that, the driver is file oriented and supports seeks, for example. Signed-off-by: Stepan Pressl --- drivers/1wire/1wire_ds2xxx.c | 829 +++++++++++++++++++++++++++++ drivers/1wire/CMakeLists.txt | 5 + drivers/1wire/Kconfig | 23 + drivers/1wire/Make.defs | 4 + include/nuttx/1wire/1wire_ds2xxx.h | 88 +++ 5 files changed, 949 insertions(+) create mode 100644 drivers/1wire/1wire_ds2xxx.c create mode 100644 include/nuttx/1wire/1wire_ds2xxx.h diff --git a/drivers/1wire/1wire_ds2xxx.c b/drivers/1wire/1wire_ds2xxx.c new file mode 100644 index 00000000000..44668714dac --- /dev/null +++ b/drivers/1wire/1wire_ds2xxx.c @@ -0,0 +1,829 @@ +/**************************************************************************** + * drivers/1wire/1wire_ds2xxx.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Author: Stepan Pressl + * + * + ****************************************************************************/ + +/* This is a driver for 1Wire Maxim Integrated DS2xxx EEPROMs. + * Currently, the driver was tested against the DS2431 EEPROM but other + * EEPROMs listed in 1wire_ds2xxx.h + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "1wire_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_ENDIAN_BIG +# define onewire_leuint64(x) (x) +# define onewire_leuint32(x) (x) +#endif + +#define WS_HEADER_OFFSET ((uint8_t)3) +#define RS_HEADER_SIZE ((uint8_t)3) +#define CS_HEADER_SIZE ((uint8_t)4) +#define HELPBUF_MARGIN ((uint8_t)5) +#define MATCHROM_BUF_SIZE ((uint8_t)9) +#define DS2XXX_TPROG_US ((useconds_t)12000) + +/**************************************************************************** + * Priavate Types + ****************************************************************************/ + +struct ds2xxx_dev_s +{ + FAR struct onewire_master_s *master; + + uint64_t romcode; /* Romcode to be addressed on the bus */ + int devtype; /* See enum ds2xxx_eeproms_e */ + uint8_t *helpbuf; /* Helpful memory to avoid alloc on stack */ + uint8_t refs; /* Opened references to ds2xxx */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int ds2xxx_open(FAR struct file *filep); +static int ds2xxx_close(FAR struct file *filep); +static int ds2xxx_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); +static ssize_t ds2xxx_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t ds2xxx_read_internal(FAR struct ds2xxx_dev_s *priv, + off_t eeprom_addr, + FAR uint8_t *buffer, size_t buflen); +static ssize_t ds2xxx_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static ssize_t ds2xxx_write_internal(FAR struct ds2xxx_dev_s *priv, + off_t eeprom_addr, + FAR uint8_t *buffer, size_t buflen); +static off_t ds2xxx_seek(FAR struct file *filep, off_t offset, int whence); +static int ds2xxx_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/* Mapping from ds2xxx_types_e to eeprom sizes, pages and family codes. + * The driver is fully generic for all supported DS2XXX memories with + * a write scratchpad. + */ + +static size_t g_eeprom_sizes[EEPROM_DS_COUNT] = +{ + 32, + 128, + 128, + 512, + 512, + 128, + 2560 +}; + +static size_t g_eeprom_scratchpad_sizes[EEPROM_DS_COUNT] = +{ + 8, + 8, + 8, + 32, + 32, + 8, + 32 +}; + +static int g_eeprom_familycodes[EEPROM_DS_COUNT] = +{ + 0x14, + 0x2d, + 0xb3, + 0x23, + 0x1c, + 0x2d, + 0x43 +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_ds2xxx_fops = +{ + .open = ds2xxx_open, + .close = ds2xxx_close, + .read = ds2xxx_read, + .write = ds2xxx_write, + .seek = ds2xxx_seek, + .ioctl = ds2xxx_ioctl, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_ENDIAN_BIG +static inline uint64_t onewire_leuint64(uint64_t x) +{ + return (((x & 0xff00000000000000ull) >> 56) | + ((x & 0x00ff000000000000ull) >> 40) | + ((x & 0x0000ff0000000000ull) >> 24) | + ((x & 0x000000ff00000000ull) >> 8) | + ((x & 0x00000000ff000000ull) << 8) | + ((x & 0x0000000000ff0000ull) << 24) | + ((x & 0x000000000000ff00ull) << 40) | + ((x & 0x00000000000000ffull) << 56)); +} +#endif + +#ifdef CONFIG_ENDIAN_BIG +static inline uint32_t onewire_leuint32(uint32_t x) +{ + return (((x & 0xff000000) >> 24) | + ((x & 0x00ff0000) >> 8) | + ((x & 0x0000ff00) << 8) | + ((x & 0x000000ff) << 24)); +} +#endif + +/**************************************************************************** + * Name: ds2xxx_startcomm + * + * Description: + * Performs the Match Rom command on the bus. + * + ****************************************************************************/ + +static int ds2xxx_startcomm(struct ds2xxx_dev_s *priv, uint8_t *wrbuf) +{ + int ret; + uint64_t tmp; + + ret = ONEWIRE_RESET(priv->master->dev); + if (ret < 0) + { + return ret; + } + + wrbuf[0] = DS2XXX_MATCH_ROM; + tmp = onewire_leuint64(priv->master->selected_rom); + memcpy(&wrbuf[1], &tmp, MATCHROM_BUF_SIZE - 1); + + return ONEWIRE_WRITE(priv->master->dev, wrbuf, MATCHROM_BUF_SIZE); +} + +/**************************************************************************** + * Name: ds2xxx_read_internal + * + * Description: + * Begins communication and reads data from the EEPROM. The read procedure + * is much simpler as data can be read from any address. + * + ****************************************************************************/ + +static ssize_t ds2xxx_read_internal(FAR struct ds2xxx_dev_s *priv, + off_t eeprom_addr, + FAR uint8_t *buffer, size_t buflen) +{ + int ret; + + /* The process of reading is much simpler. + * The master must issue the Read Memory command followed with 2 bytes + * of address to be read from. The address is sent in little endian order. + */ + + /* Initialize the communication */ + + ret = ds2xxx_startcomm(priv, buffer); + if (ret < 0) + { + return ret; + } + + priv->helpbuf[0] = DS2XXX_READ_MEMORY; + priv->helpbuf[1] = eeprom_addr & 0xff; + priv->helpbuf[2] = eeprom_addr >> 8; + ret = ONEWIRE_WRITE(priv->master->dev, priv->helpbuf, 3); + if (ret < 0) + { + return ret; + } + + /* Now read real data. */ + + ret = ONEWIRE_READ(priv->master->dev, (uint8_t *)buffer, buflen); + return ret; +} + +/**************************************************************************** + * Name: ds2xxx_write_internal + * + * Description: + * Begins communication and reads data from the EEPROM. The write procedure + * is not that straightforward. It is assumed the writes by this function + * are aligned. It is assumed buflen is at most the size of the scratchpad. + * + ****************************************************************************/ + +static ssize_t ds2xxx_write_internal(FAR struct ds2xxx_dev_s *priv, + off_t eeprom_addr, + FAR uint8_t *buffer, size_t buflen) +{ + ssize_t ret; + uint8_t buf[32 + HELPBUF_MARGIN]; + uint16_t crc; + uint16_t reccrc; + + i2cinfo("writing %zu bytes to %ld", buflen, eeprom_addr); + + ret = ds2xxx_startcomm(priv, buf); + if (ret < 0) + { + return ret; + } + + /* Now issue the write scratchpad command. Also calculate + * CRC16 which must be compared with the received one. + */ + + buf[0] = DS2XXX_WRITE_SCRATCHPAD; + buf[1] = eeprom_addr & 0xff; + buf[2] = eeprom_addr >> 8; + crc = onewire_crc16(buf, 3, 0); + + ret = ONEWIRE_WRITE(priv->master->dev, buf, 3); + if (ret < 0) + { + return ret; + } + + crc = onewire_crc16(buffer, buflen, crc); + ret = ONEWIRE_WRITE(priv->master->dev, buffer, buflen); + if (ret < 0) + { + return ret; + } + + /* We now need to receive the CRC. The order is little endian. */ + + ret = ONEWIRE_READ(priv->master->dev, buf, 2); + if (ret < 0) + { + return ret; + } + + reccrc = buf[0] | (buf[1] << 8); + if (reccrc != (uint16_t) ~crc) + { + return -EPROTO; + } + + /* We have successfully performed the Write Scratchpad command. + * Now issue read scratchpad. + */ + + ret = ds2xxx_startcomm(priv, buf); + if (ret < 0) + { + return ret; + } + + buf[0] = DS2XXX_READ_SCRATCHPAD; + ret = ONEWIRE_WRITE(priv->master->dev, buf, 1); + if (ret < 0) + { + return ret; + } + + crc = onewire_crc16(buf, 1, 0); + + /* TA-E/S + buflen + ~CRC16 => buflen + 5 */ + + ret = ONEWIRE_READ(priv->master->dev, buf, + buflen + HELPBUF_MARGIN); + if (ret < 0) + { + return ret; + } + + crc = onewire_crc16(buf, buflen + RS_HEADER_SIZE, crc); + reccrc = buf[RS_HEADER_SIZE + buflen] | + buf[RS_HEADER_SIZE + buflen + 1] << 8; + if (reccrc != (uint16_t) ~crc) + { + return -EPROTO; + } + + /* Memcheck should be performed, but imho CRC16 is already a good check. + * Commit the scratchpad into the eeprom. + */ + + priv->helpbuf[0] = DS2XXX_COPY_SCRATCHPAD; + priv->helpbuf[1] = buf[0]; + priv->helpbuf[2] = buf[1]; + priv->helpbuf[3] = buf[2]; + ret = ds2xxx_startcomm(priv, buf); + if (ret < 0) + { + return ret; + } + + ret = ONEWIRE_WRITE(priv->master->dev, priv->helpbuf, CS_HEADER_SIZE); + if (ret < 0) + { + return ret; + } + + /* Impose a delay. Across all supported devices, the maximum delay is 12 ms + * for a page. + */ + + up_udelay(DS2XXX_TPROG_US); + + i2cinfo("aligned write of %zu bytes successful", buflen); + return OK; +} + +/**************************************************************************** + * Name: ds2xxx_open + * + * Description: + * The open callback function. + * + ****************************************************************************/ + +static int ds2xxx_open(FAR struct file *filep) +{ + FAR struct ds2xxx_dev_s *priv; + FAR struct inode *inode = filep->f_inode; + int ret = OK; + + DEBUGASSERT(inode->i_private); + priv = inode->i_private; + + ret = nxrmutex_lock(&priv->master->devlock); + if (ret < 0) + { + return ret; + } + + if ((priv->refs + 1) == 0) + { + ret = -EMFILE; + } + else + { + priv->refs++; + } + + nxrmutex_unlock(&priv->master->devlock); + return OK; +} + +/**************************************************************************** + * Name: ds2xxx_write + * + * Description: + * The write callback function. As writes into the EEPROM must be aligned + * with the scratchpad, all nonaligned writes must first read the aligned + * part, change some bytes and then commit the aligned part to the + * scratchpad. This function takes care of this. + * + ****************************************************************************/ + +static int ds2xxx_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct ds2xxx_dev_s *priv; + FAR struct inode *inode = filep->f_inode; + off_t addr; + off_t misalign; + size_t to_write; + size_t scratchpad_size; + size_t buflen_save = buflen; + int ret = OK; + + DEBUGASSERT(inode->i_private); + priv = inode->i_private; + scratchpad_size = g_eeprom_scratchpad_sizes[priv->devtype]; + + i2cwarn("writing %zu bytes to ptr %" PRIdOFF, buflen, filep->f_pos); + + if (filep->f_pos >= g_eeprom_sizes[priv->devtype]) + { + return -EFBIG; + } + + if ((filep->f_pos + buflen) >= g_eeprom_sizes[priv->devtype]) + { + buflen = g_eeprom_sizes[priv->devtype] - filep->f_pos; + buflen_save = buflen; + } + + ret = nxrmutex_lock(&priv->master->devlock); + if (ret < 0) + { + goto done; + } + + /* The process of writing to 1WIRE EEPROMs involves the usage + * of the scratchpad. Firstly, the Write Scratchpad command + * must be issued, the payload is as follows: + * 2 bytes ADDR (Little Endian) | DATA, + * where ADDR must be aligned to the scratchpad size + * (DS2431's scratchpad is 8 bytes, DS2433's scratchpad is 32 bytes + * and the DATA is maximally 8 bytes or 32 bytes, depending on the EEPROM. + * + * Since writes are not generally row aligned, we must read + * the corresponding unaligned ends beforehand, modifying respective parts + * and writing this back. + * + * To check the transaction has completed successfully, Read Scratchpad + * command is issued, returning the 3-byte authorization pattern, also. + * + * The writing procedure is ended with issuing the Copy Scratchpad + * command. + */ + + /* Calculate the misalignment in the beginning. And the starting address. */ + + misalign = (filep->f_pos) % scratchpad_size; + addr = (filep->f_pos / scratchpad_size) * scratchpad_size; + + /* The pointer points at the beginning of a page, decide if we skip. */ + + if (misalign == 0) + { + goto no_misalign_begin; + } + + ret = ds2xxx_read_internal(priv, addr, priv->helpbuf, scratchpad_size); + if (ret < 0) + { + goto done; + } + + /* Fill in the misaligned data. But decide on the length of the write. */ + + if (buflen >= scratchpad_size - misalign) + { + to_write = scratchpad_size - misalign; + } + else + { + to_write = buflen; + } + + memcpy(priv->helpbuf + misalign, buffer, to_write); + ret = ds2xxx_write_internal(priv, addr, priv->helpbuf, scratchpad_size); + if (ret < 0) + { + goto done; + } + + /* Move all the pointers */ + + buffer += to_write; + buflen -= to_write; + addr += scratchpad_size; + +no_misalign_begin: + + /* Now loop over all aligned writes. If everything was already + * written in the misaligned write or the next write is also misaligned, + * this loop won't run. + */ + + while (buflen >= scratchpad_size) + { + ret = ds2xxx_write_internal(priv, addr, (uint8_t *)buffer, + scratchpad_size); + if (ret < 0) + { + goto done; + } + + buffer += scratchpad_size; + buflen -= scratchpad_size; + addr += scratchpad_size; + } + + /* There's no rest. */ + + if (buflen == 0) + { + goto success; + } + + /* Finish this with the last read. The read is aligned but needs to be + * of the same size as the scratchpad. + */ + + ret = ds2xxx_read_internal(priv, addr, priv->helpbuf, scratchpad_size); + if (ret < 0) + { + goto done; + } + + memcpy(priv->helpbuf, buffer, buflen); + ret = ds2xxx_write_internal(priv, addr, priv->helpbuf, scratchpad_size); + if (ret < 0) + { + goto done; + } + + /* Everything went well. Move the pointer */ + +success: + i2cwarn("success writing %d bytes", buflen_save); + filep->f_pos += buflen_save; + ret = buflen_save; +done: + nxrmutex_unlock(&priv->master->devlock); + return ret; +} + +/**************************************************************************** + * Name: ds2xxx_read + * + * Description: + * The read callback function. First, it checks the boundaries and then + * calls the ds2xxx_read_internal function. + * + ****************************************************************************/ + +static ssize_t ds2xxx_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct ds2xxx_dev_s *priv; + FAR struct inode *inode = filep->f_inode; + int ret = OK; + + DEBUGASSERT(inode->i_private); + priv = inode->i_private; + + ret = nxrmutex_lock(&priv->master->devlock); + if (ret < 0) + { + return ret; + } + + /* The pointer is outside the "file" */ + + if (filep->f_pos >= g_eeprom_sizes[priv->devtype]) + { + goto done; + } + + /* Trim the length */ + + if ((filep->f_pos + len) > g_eeprom_sizes[priv->devtype]) + { + len = g_eeprom_sizes[priv->devtype] - filep->f_pos; + } + + ret = ds2xxx_read_internal(priv, filep->f_pos, (uint8_t *)buffer, len); + if (ret < 0) + { + goto done; + } + + ret = len; + filep->f_pos += len; + + i2cinfo("DS2XXX read OK, curpos=%" PRIdOFF, filep->f_pos); + +done: + nxrmutex_unlock(&priv->master->devlock); + return ret; +} + +/**************************************************************************** + * Name: ds2xxx_close + * + * Description: + * The close callback function. + * + ****************************************************************************/ + +static int ds2xxx_close(FAR struct file *filep) +{ + FAR struct ds2xxx_dev_s *priv; + FAR struct inode *inode = filep->f_inode; + int ret = OK; + + DEBUGASSERT(inode->i_private); + priv = inode->i_private; + + ret = nxrmutex_lock(&priv->master->devlock); + if (ret < 0) + { + return ret; + } + + if (priv->refs == 0) + { + ret = -EIO; + } + else + { + priv->refs--; + } + + nxrmutex_unlock(&priv->master->devlock); + return ret; +} + +/**************************************************************************** + * Name: ds2xxx_seek + * + * Description: + * The seek callback function. Practically the same as in i2c_xx24xx.c. + * + ****************************************************************************/ + +static off_t ds2xxx_seek(FAR struct file *filep, off_t offset, int whence) +{ + FAR struct ds2xxx_dev_s *priv; + FAR struct inode *inode = filep->f_inode; + int ret; + off_t newpos; + + DEBUGASSERT(inode->i_private); + priv = inode->i_private; + + ret = nxrmutex_lock(&priv->master->devlock); + if (ret < 0) + { + return ret; + } + + switch (whence) + { + case SEEK_CUR: + newpos = filep->f_pos + offset; + break; + case SEEK_SET: + newpos = offset; + break; + case SEEK_END: + newpos = g_eeprom_sizes[priv->devtype] + offset; + break; + default: + nxrmutex_unlock(&priv->master->devlock); + return -EINVAL; + } + + /* Opengroup.org: + * + * "The lseek() function shall allow the file offset to be set beyond the + * end of the existing data in the file. If data is later written at + * this point, subsequent reads of data in the gap shall return bytes + * with the value 0 until data is actually written into the gap." + * + * We can conform to the first part, but not the second. But return -EINVAL + * if + * + * "...the resulting file offset would be negative for a regular file, + * block special file, or directory." + */ + + if (newpos >= 0) + { + filep->f_pos = newpos; + ret = newpos; + i2cinfo("ds2xxx_seek: newpos %" PRIdOFF, newpos); + } + else + { + ret = -EINVAL; + } + + nxrmutex_unlock(&priv->master->devlock); + return ret; +} + +/**************************************************************************** + * Name: ds2xxx_ioctl + * + * Description: + * The ioctl callback function. The target romcode is specified here. + * + ****************************************************************************/ + +static int ds2xxx_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct ds2xxx_dev_s *priv; + FAR struct inode *inode = filep->f_inode; + int ret = OK; + + DEBUGASSERT(inode->i_private); + priv = inode->i_private; + + nxrmutex_lock(&priv->master->devlock); + switch (cmd) + { + case ONEWIREIOC_SETROM: + /* The issue is that unsigned long is 32bits on most architectures. + * That means we should not pass the romcode as a value. + */ + + i2cinfo("Rom to be set is 0x%" PRIx64, *((uint64_t *)arg)); + ret = onewire_ioctl_setrom(priv->master, *((uint64_t *)arg)); + break; + case ONEWIREIOC_GETFAMILYROMS: + ret = onewire_ioctl_getfamilyroms(priv->master, + (FAR struct onewire_availroms_s *)arg, + g_eeprom_familycodes[priv->devtype]); + break; + default: + ret = -ENOTTY; + } + + nxrmutex_unlock(&priv->master->devlock); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int ds2xxx_initialize(FAR struct onewire_dev_s *dev, + enum ds2xxx_eeproms_e devtype, FAR char *devname) +{ + FAR struct ds2xxx_dev_s *priv; + + if (devtype < 0 || devtype > EEPROM_DS_COUNT) + { + return -EINVAL; + } + + priv = kmm_zalloc(sizeof(struct ds2xxx_dev_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->master = onewire_initialize(dev, CONFIG_1WIRE_EE_DS2XXX_MEMSONBUS); + if (priv->master == NULL) + { + kmm_free(priv); + return -ENOMEM; + } + + /* We need extra 5 bytes for the Copy Scratchpad command. */ + + priv->helpbuf = kmm_zalloc(HELPBUF_MARGIN + + g_eeprom_scratchpad_sizes[devtype]); + if (priv->helpbuf == NULL) + { + kmm_free(priv->master); + kmm_free(priv); + return -ENOMEM; + } + + nxrmutex_init(&priv->master->devlock); + priv->master->dev = dev; + priv->devtype = devtype; + + return register_driver(devname, &g_ds2xxx_fops, 0666, priv); +} diff --git a/drivers/1wire/CMakeLists.txt b/drivers/1wire/CMakeLists.txt index b4b0cdc84cd..dbfac2e4747 100644 --- a/drivers/1wire/CMakeLists.txt +++ b/drivers/1wire/CMakeLists.txt @@ -27,5 +27,10 @@ if(CONFIG_1WIRE) list(APPEND SRCS ds28e17.c) endif() + # Include the 1WIRE driver for DS2XXX EEPROMs + if(CONFIG_1WIRE_EE_DS2XXX) + list(APPEND SRCS 1wire_ds2xxx.c) + endif() + target_sources(drivers PRIVATE ${SRCS}) endif() diff --git a/drivers/1wire/Kconfig b/drivers/1wire/Kconfig index bdf1a8cea55..7ab14c538d3 100644 --- a/drivers/1wire/Kconfig +++ b/drivers/1wire/Kconfig @@ -18,4 +18,27 @@ config 1WIRE_DS28E17 ---help--- Enable support for the Maxim DS28E17 1-wire to I2C converter +config 1WIRE_EE_DS2XXX + bool "Support for Maxim/Analog Devices 1wire DS2XXX EEPROM devices" + default n + depends on 1WIRE + ---help--- + Enable support for 1WIRE DS2XXX EEPROMs. + The list of supported devices: + DS2430: 32 bytes, 1 page + DS2431: 128 bytes, 4 pages + DS2432: 128 bytes, 4 pages + DS2433: 512 bytes, 16 pages + DS28E04: 512 bytes, 16 pages + DS28E07: 128 bytes, 4 pages + DS28EC20: 2560 bytes, 32 pages + +if 1WIRE_EE_DS2XXX + +config 1WIRE_EE_DS2XXX_MEMSONBUS + int "Maximum number of DS2XXX eeproms on the same bus" + default 10 + +endif # 1WIRE_EE_DS2XXX + endif # 1WIRE diff --git a/drivers/1wire/Make.defs b/drivers/1wire/Make.defs index 01695e3e3cc..f01d6bc9acb 100644 --- a/drivers/1wire/Make.defs +++ b/drivers/1wire/Make.defs @@ -28,6 +28,10 @@ ifeq ($(CONFIG_1WIRE_DS28E17),y) CSRCS += ds28e17.c endif +ifeq ($(CONFIG_1WIRE_EE_DS2XXX),y) +CSRCS += 1wire_ds2xxx.c +endif + # Include 1wire device driver build support DEPPATH += --dep-path 1wire diff --git a/include/nuttx/1wire/1wire_ds2xxx.h b/include/nuttx/1wire/1wire_ds2xxx.h new file mode 100644 index 00000000000..2c983c1d3c8 --- /dev/null +++ b/include/nuttx/1wire/1wire_ds2xxx.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * include/nuttx/1wire/1wire_ds2xxx.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Author: Stepan Pressl + * + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_EEPROM_1WIRE_DS2XXX_H +#define __INCLUDE_NUTTX_EEPROM_1WIRE_DS2XXX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* All device specific commands for the scratchpad are luckily the same + * for all the devices. + */ + +#define DS2XXX_WRITE_SCRATCHPAD 0x0f +#define DS2XXX_READ_SCRATCHPAD 0xaa +#define DS2XXX_COPY_SCRATCHPAD 0x55 +#define DS2XXX_READ_MEMORY 0xf0 + +/* There are other commands, also. For example, the common commands + * have a different code than specified in drivers/1wire/1wire.c. + */ + +#define DS2XXX_MATCH_ROM 0x55 + +/* DS28E05 has a different architecture, + * as it does not use a scratchpad. Let's keep this device out of here. + */ + +enum ds2xxx_eeproms_e +{ + EEPROM_DS2430 = 0, + EEPROM_DS2431, + EEPROM_DS2432, + EEPROM_DS2433, + EEPROM_DS28E04, + EEPROM_DS28E07, + EEPROM_DS28EC20, + EEPROM_DS_COUNT +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ds2xxx_initialize + * + * Description: Bind a onewire_master_s struct to this driver, + * capable of interfacing DS2XXX 1Wire EEPROMs. The user must specify + * the device type and also the name of the device (e.g. /dev/ds2xxx). + * + ****************************************************************************/ + +int ds2xxx_initialize(FAR struct onewire_dev_s *dev, + enum ds2xxx_eeproms_e devtype, FAR char *devname); + +#endif /* __INCLUDE_NUTTX_EEPROM_1WIRE_DS2XXX_H */