zephyr/drivers/w1/w1_ds2484.c

180 lines
4.8 KiB
C

/*
* Copyright (c) 2022 Caspar Friedrich <c.s.w.friedrich@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "w1_ds248x.h"
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/w1.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <zephyr/kernel.h>
#define DT_DRV_COMPAT maxim_ds2484
LOG_MODULE_REGISTER(ds2484, CONFIG_W1_LOG_LEVEL);
struct ds2484_config {
struct w1_master_config w1_config;
const struct i2c_dt_spec i2c_spec;
const struct gpio_dt_spec slpz_spec;
bool apu;
};
struct ds2484_data {
struct w1_master_data w1_data;
uint8_t reg_device_config;
};
static int ds2484_reset_bus(const struct device *dev)
{
const struct ds2484_config *config = dev->config;
return ds248x_reset_bus(&config->i2c_spec);
}
static int ds2484_read_bit(const struct device *dev)
{
const struct ds2484_config *config = dev->config;
return ds248x_read_bit(&config->i2c_spec);
}
static int ds2484_write_bit(const struct device *dev, bool bit)
{
const struct ds2484_config *config = dev->config;
return ds248x_write_bit(&config->i2c_spec, bit);
}
static int ds2484_read_byte(const struct device *dev)
{
const struct ds2484_config *config = dev->config;
return ds248x_read_byte(&config->i2c_spec);
}
static int ds2484_write_byte(const struct device *dev, uint8_t byte)
{
const struct ds2484_config *config = dev->config;
return ds248x_write_byte(&config->i2c_spec, byte);
}
static int ds2484_configure(const struct device *dev, enum w1_settings_type type, uint32_t value)
{
const struct ds2484_config *config = dev->config;
struct ds2484_data *data = dev->data;
switch (type) {
case W1_SETTING_SPEED:
WRITE_BIT(data->reg_device_config, DEVICE_1WS_pos, value);
break;
case W1_SETTING_STRONG_PULLUP:
WRITE_BIT(data->reg_device_config, DEVICE_SPU_pos, value);
break;
default:
return -EINVAL;
}
return ds248x_write_config(&config->i2c_spec, data->reg_device_config);
}
#ifdef CONFIG_PM_DEVICE
static int ds2484_pm_control(const struct device *dev, enum pm_device_action action)
{
const struct ds2484_config *config = dev->config;
switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
if (!config->slpz_spec.port) {
return -ENOTSUP;
}
return gpio_pin_set_dt(&config->slpz_spec, 1);
case PM_DEVICE_ACTION_RESUME:
if (!config->slpz_spec.port) {
return -ENOTSUP;
}
return gpio_pin_set_dt(&config->slpz_spec, 0);
default:
return -ENOTSUP;
};
return 0;
}
#endif /* CONFIG_PM_DEVICE */
static int ds2484_init(const struct device *dev)
{
int ret;
const struct ds2484_config *config = dev->config;
struct ds2484_data *data = dev->data;
if (config->slpz_spec.port) {
if (!device_is_ready(config->slpz_spec.port)) {
LOG_ERR("Port (SLPZ) not ready");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&config->slpz_spec, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Pin configuration (SLPZ) failed: %d", ret);
return ret;
}
}
if (!device_is_ready(config->i2c_spec.bus)) {
return -ENODEV;
}
ret = ds248x_reset_device(&config->i2c_spec);
if (ret < 0) {
LOG_ERR("Device reset failed: %d", ret);
return ret;
}
WRITE_BIT(data->reg_device_config, DEVICE_APU_pos, config->apu);
ret = ds248x_write_config(&config->i2c_spec, data->reg_device_config);
if (ret < 0) {
LOG_ERR("Device config update failed: %d", ret);
return ret;
}
return 0;
}
static const struct w1_driver_api ds2484_driver_api = {
.reset_bus = ds2484_reset_bus,
.read_bit = ds2484_read_bit,
.write_bit = ds2484_write_bit,
.read_byte = ds2484_read_byte,
.write_byte = ds2484_write_byte,
.configure = ds2484_configure,
};
#define DS2484_INIT(inst) \
static const struct ds2484_config inst_##inst##_config = { \
.w1_config.slave_count = W1_INST_SLAVE_COUNT(inst), \
.i2c_spec = I2C_DT_SPEC_INST_GET(inst), \
.slpz_spec = GPIO_DT_SPEC_INST_GET_OR(inst, slpz_gpios, {0}), \
.apu = DT_INST_PROP(inst, active_pullup), \
}; \
static struct ds2484_data inst_##inst##_data; \
PM_DEVICE_DT_INST_DEFINE(inst, ds2484_pm_control); \
DEVICE_DT_INST_DEFINE(inst, ds2484_init, PM_DEVICE_DT_INST_GET(inst), &inst_##inst##_data, \
&inst_##inst##_config, POST_KERNEL, CONFIG_W1_INIT_PRIORITY, \
&ds2484_driver_api);
DT_INST_FOREACH_STATUS_OKAY(DS2484_INIT)
/*
* Make sure that this driver is not initialized before the i2c bus is available
*/
BUILD_ASSERT(CONFIG_W1_INIT_PRIORITY > CONFIG_I2C_INIT_PRIORITY);