|  | /* | 
|  | * Copyright (c) 2022 Caspar Friedrich <c.s.w.friedrich@gmail.com> | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #ifndef ZEPHYR_DRIVERS_W1_W1_DS248X_H_ | 
|  | #define ZEPHYR_DRIVERS_W1_W1_DS248X_H_ | 
|  |  | 
|  | #include <zephyr/drivers/i2c.h> | 
|  | #include <zephyr/kernel.h> | 
|  |  | 
|  | #define CMD_1WT	 0x78 | 
|  | #define CMD_1WSB 0x87 | 
|  | #define CMD_1WRB 0x96 | 
|  | #define CMD_1WWB 0xa5 | 
|  | #define CMD_1WRS 0xb4 | 
|  | #define CMD_CHSL 0xc3 /* DS2482-800 only */ | 
|  | #define CMD_ADJP 0xc3 /* DS2484 only */ | 
|  | #define CMD_WCFG 0xd2 | 
|  | #define CMD_SRP	 0xe1 | 
|  | #define CMD_DRST 0xf0 | 
|  |  | 
|  | #define REG_NONE    0x00 /* special value */ | 
|  | #define REG_CONFIG  0xc3 | 
|  | #define REG_DATA    0xe1 | 
|  | #define REG_STATUS  0xf0 | 
|  | #define REG_CHANNEL 0xd2 /* DS2482-800 only */ | 
|  | #define REG_PORT    0xb4 /* DS2484 only */ | 
|  |  | 
|  | /* | 
|  | * Device Configuration Register | 
|  | */ | 
|  | #define DEVICE_APU_pos 0 | 
|  | #define DEVICE_APU_msk BIT(DEVICE_APU_pos) | 
|  | #define DEVICE_PDN_pos 1		   /* DS2484 only */ | 
|  | #define DEVICE_PDN_msk BIT(DEVICE_PDN_pos) /* DS2484 only */ | 
|  | #define DEVICE_SPU_pos 2 | 
|  | #define DEVICE_SPU_msk BIT(DEVICE_SPU_pos) | 
|  | #define DEVICE_1WS_pos 3 | 
|  | #define DEVICE_1WS_msk BIT(DEVICE_1WS_pos) | 
|  |  | 
|  | /* | 
|  | * Status Register | 
|  | */ | 
|  | #define STATUS_1WB_pos 0 | 
|  | #define STATUS_1WB_msk BIT(STATUS_1WB_pos) | 
|  | #define STATUS_PPD_pos 1 | 
|  | #define STATUS_PPD_msk BIT(STATUS_PPD_pos) | 
|  | #define STATUS_SD_pos  2 | 
|  | #define STATUS_SD_msk  BIT(STATUS_SD_pos) | 
|  | #define STATUS_LL_pos  3 | 
|  | #define STATUS_LL_msk  BIT(STATUS_LL_pos) | 
|  | #define STATUS_RST_pos 4 | 
|  | #define STATUS_RST_msk BIT(STATUS_RST_pos) | 
|  | #define STATUS_SBR_pos 5 | 
|  | #define STATUS_SBR_msk BIT(STATUS_SBR_pos) | 
|  | #define STATUS_TSB_pos 6 | 
|  | #define STATUS_TSB_msk BIT(STATUS_TSB_pos) | 
|  | #define STATUS_DIR_pos 7 | 
|  | #define STATUS_DIR_msk BIT(STATUS_DIR_pos) | 
|  |  | 
|  | /* | 
|  | * Channel Selection Codes, DS2482-800 only | 
|  | */ | 
|  | #define CHSL_IO0 0xf0 | 
|  | #define CHSL_IO1 0xe1 | 
|  | #define CHSL_IO2 0xd2 | 
|  | #define CHSL_IO3 0xc3 | 
|  | #define CHSL_IO4 0xb4 | 
|  | #define CHSL_IO5 0xa5 | 
|  | #define CHSL_IO6 0x96 | 
|  | #define CHSL_IO7 0x87 | 
|  |  | 
|  | /* | 
|  | * Channel Selection Codes (read back values), DS2482-800 only | 
|  | */ | 
|  | #define CHSL_IO0_RB 0xb8 | 
|  | #define CHSL_IO1_RB 0xb1 | 
|  | #define CHSL_IO2_RB 0xaa | 
|  | #define CHSL_IO3_RB 0xa3 | 
|  | #define CHSL_IO4_RB 0x9c | 
|  | #define CHSL_IO5_RB 0x95 | 
|  | #define CHSL_IO6_RB 0x8e | 
|  | #define CHSL_IO7_RB 0x87 | 
|  |  | 
|  | /* | 
|  | * Port Configuration Register, DS2484 only | 
|  | */ | 
|  | #define PORT_VAL0_pos 0 | 
|  | #define PORT_VAL0_msk BIT(PORT_VAL0_pos) | 
|  | #define PORT_VAL1_pos 1 | 
|  | #define PORT_VAL1_msk BIT(PORT_VAL1_pos) | 
|  | #define PORT_VAL2_pos 2 | 
|  | #define PORT_VAL2_msk BIT(PORT_VAL2_pos) | 
|  | #define PORT_VAL3_pos 3 | 
|  | #define PORT_VAL3_msk BIT(PORT_VAL3_pos) | 
|  |  | 
|  | /* | 
|  | * Bit Byte | 
|  | */ | 
|  | #define BIT_CLR_msk 0 | 
|  | #define BIT_SET_msk BIT(7) | 
|  |  | 
|  | static inline int ds248x_write(const struct i2c_dt_spec *spec, uint8_t cmd, uint8_t *data) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | const uint8_t buf[] = {cmd, data ? *data : 0}; | 
|  |  | 
|  | ret = i2c_write_dt(spec, buf, data ? 2 : 1); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_read(const struct i2c_dt_spec *spec, uint8_t rp, uint8_t *reg) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | switch (rp) { | 
|  | case REG_NONE: | 
|  | /* | 
|  | * Special value: Don't change read pointer | 
|  | */ | 
|  | break; | 
|  | case REG_PORT: | 
|  | __fallthrough; | 
|  | case REG_CONFIG: | 
|  | __fallthrough; | 
|  | case REG_CHANNEL: | 
|  | __fallthrough; | 
|  | case REG_DATA: | 
|  | __fallthrough; | 
|  | case REG_STATUS: | 
|  | ret = ds248x_write(spec, CMD_SRP, &rp); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | ret = i2c_read_dt(spec, reg, 1); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_reset_bus(const struct i2c_dt_spec *spec) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | uint8_t reg; | 
|  |  | 
|  | ret = ds248x_write(spec, CMD_1WRS, NULL); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | do { | 
|  | ret = ds248x_read(spec, REG_NONE, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } while (reg & STATUS_1WB_msk); | 
|  |  | 
|  | return reg & STATUS_PPD_msk ? 1 : 0; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_reset_device(const struct i2c_dt_spec *spec) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | uint8_t reg; | 
|  |  | 
|  | ret = ds248x_write(spec, CMD_DRST, NULL); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | do { | 
|  | ret = ds248x_read(spec, REG_NONE, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } while (!(reg & STATUS_RST_msk)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ds248x_single_bit(const struct i2c_dt_spec *spec, uint8_t bit_msk) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | uint8_t reg; | 
|  |  | 
|  | ret = ds248x_write(spec, CMD_1WSB, &bit_msk); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | do { | 
|  | ret = ds248x_read(spec, REG_NONE, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } while (reg & STATUS_1WB_msk); | 
|  |  | 
|  | return reg & STATUS_SBR_msk; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_read_bit(const struct i2c_dt_spec *spec) | 
|  | { | 
|  | int ret = ds248x_single_bit(spec, BIT_SET_msk); | 
|  |  | 
|  | return ret > 1 ? 1 : ret; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_write_bit(const struct i2c_dt_spec *spec, bool bit) | 
|  | { | 
|  | int ret = ds248x_single_bit(spec, bit ? BIT_SET_msk : BIT_CLR_msk); | 
|  |  | 
|  | return ret > 0 ? 0 : ret; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_read_byte(const struct i2c_dt_spec *spec) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | uint8_t reg; | 
|  |  | 
|  | ret = ds248x_write(spec, CMD_1WRB, NULL); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | do { | 
|  | ret = ds248x_read(spec, REG_NONE, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } while (reg & STATUS_1WB_msk); | 
|  |  | 
|  | ret = ds248x_read(spec, REG_DATA, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return reg; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_write_byte(const struct i2c_dt_spec *spec, uint8_t byte) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | uint8_t reg; | 
|  |  | 
|  | ret = ds248x_write(spec, CMD_1WWB, &byte); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | do { | 
|  | ret = ds248x_read(spec, REG_NONE, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  | } while (reg & STATUS_1WB_msk); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline int ds248x_write_config(const struct i2c_dt_spec *spec, uint8_t cfg) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | uint8_t reg = cfg | ~cfg << 4; | 
|  |  | 
|  | if (cfg & ~(DEVICE_APU_msk | DEVICE_PDN_msk | DEVICE_SPU_msk | DEVICE_1WS_msk)) { | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | ret = ds248x_write(spec, CMD_WCFG, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ret = ds248x_read(spec, REG_NONE, ®); | 
|  | if (ret < 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return (reg == cfg) ? 0 : -EIO; | 
|  | } | 
|  |  | 
|  | #endif /* ZEPHYR_DRIVERS_W1_W1_DS248X_H_ */ |