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