303 lines
5.7 KiB
C
303 lines
5.7 KiB
C
/*
|
|
* 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_ */
|