| /* |
| * 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); |