/* fdc2x1x.c - Driver for the Texas Instruments FDC2X1X */ /* * Copyright (c) 2020 arithmetics.io * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT ti_fdc2x1x #include #include #include #include #include #include "fdc2x1x.h" #include LOG_MODULE_REGISTER(FDC2X1X, CONFIG_SENSOR_LOG_LEVEL); static int fdc2x1x_init_config(const struct device *dev); /** * Convert raw data to frequency (MHz). * @param dev - The device structure. * @param ch - Channel to convert the data from. * @param freq - Calculated frequency value . */ static void fdc2x1x_raw_to_freq(const struct device *dev, uint8_t ch, double *freq) { struct fdc2x1x_data *data = dev->data; const struct fdc2x1x_config *cfg = dev->config; if (data->fdc221x) { *freq = (cfg->ch_cfg->fin_sel * (cfg->fref / 1000.0) * data->channel_buf[ch]) / pow(2, 28); } else { *freq = cfg->ch_cfg->fin_sel * (cfg->fref / 1000.0) * ((data->channel_buf[ch] / pow(2, 12 + cfg->output_gain)) + (cfg->ch_cfg[ch].offset / pow(2, 16))); } } /** * Convert raw data to capacitance in picofarad (pF). * Requires the previous conversion from raw to frequency. * @param dev - The device structure. * @param ch - Channel to convert the data from . * @param freq - Frequency value * @param capacitance - Calculated capacitance value */ static void fdc2x1x_raw_to_capacitance(const struct device *dev, uint8_t ch, double freq, double *capacitance) { const struct fdc2x1x_config *cfg = dev->config; *capacitance = 1 / ((cfg->ch_cfg->inductance / 1000000.0) * pow((2 * PI * freq), 2)); } /** * Read/Write from device. * @param dev - The device structure. * @param reg - The register address. Use FDC2X1X_REG_READ(x) or * FDC2X1X_REG_WRITE(x). * @param data - The register data. * @param length - Number of bytes being read * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_bus_access(const struct device *dev, uint8_t reg, uint8_t *data, size_t length) { const struct fdc2x1x_config *cfg = dev->config; if (reg & FDC2X1X_READ) { return i2c_burst_read_dt(&cfg->i2c, FDC2X1X_TO_I2C_REG(reg), data, length); } else { if (length != 2) { return -EINVAL; } uint8_t buf[3]; buf[0] = FDC2X1X_TO_I2C_REG(reg); memcpy(buf + 1, data, sizeof(uint16_t)); return i2c_write_dt(&cfg->i2c, buf, sizeof(buf)); } } /** * Read (16 Bit) from device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_reg_read(const struct device *dev, uint8_t reg_addr, uint16_t *reg_data) { uint8_t buf[2]; int ret; ret = fdc2x1x_bus_access(dev, FDC2X1X_REG_READ(reg_addr), buf, 2); *reg_data = ((uint16_t)buf[0] << 8) | buf[1]; return ret; } /** * Write (16 Bit) to device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_reg_write(const struct device *dev, uint8_t reg_addr, uint16_t reg_data) { LOG_DBG("[0x%x] = 0x%x", reg_addr, reg_data); uint8_t buf[2]; buf[0] = (uint8_t)(reg_data >> 8); buf[1] = (uint8_t)reg_data; return fdc2x1x_bus_access(dev, FDC2X1X_REG_WRITE(reg_addr), buf, 2); } /** * I2C write (16 Bit) to device using a mask. * @param dev - The device structure. * @param reg_addr - The register address. * @param mask - The mask. * @param data - The register data. * @return 0 in case of success, negative error code otherwise. */ int fdc2x1x_reg_write_mask(const struct device *dev, uint8_t reg_addr, uint16_t mask, uint16_t data) { int ret; uint16_t tmp; ret = fdc2x1x_reg_read(dev, reg_addr, &tmp); if (ret) { return ret; } LOG_DBG("read [0x%x] = 0x%x", reg_addr, tmp); LOG_DBG("mask: 0x%x", mask); tmp &= ~mask; tmp |= data; return fdc2x1x_reg_write(dev, reg_addr, tmp); } /** * Set the Frequency Selection value of a specific channel. * @param dev - The device structure. * @param chx - Channel number. * @param fin_sel - Frequency selection value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_fin_sel(const struct device *dev, uint8_t chx, uint8_t fin_sel) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CLOCK_DIVIDERS_CH0 + chx, FDC2X1X_CLK_DIV_CHX_FIN_SEL_MSK, FDC2X1X_CLK_DIV_CHX_FIN_SEL_SET(fin_sel)); } /** * Set the Reference Divider value of a specific channel. * @param dev - The device structure. * @param chx - Channel number. * @param fref_div - Reference divider value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_fref_divider(const struct device *dev, uint8_t chx, uint16_t fref_div) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CLOCK_DIVIDERS_CH0 + chx, FDC2X1X_CLK_DIV_CHX_FREF_DIV_MSK, FDC2X1X_CLK_DIV_CHX_FREF_DIV_SET(fref_div)); } /** * Set the Drive Current value of a specific channel. * @param dev - The device structure. * @param chx - Channel number. * @param idrv - Sensor driver current. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_idrive(const struct device *dev, uint8_t chx, uint8_t idrv) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_DRIVE_CURRENT_CH0 + chx, FDC2X1X_DRV_CURRENT_CHX_IDRIVE_MSK, FDC2X1X_DRV_CURRENT_CHX_IDRIVE_SET(idrv)); } /** * Set the Conversion Settling value of a specific channel. * @param dev - The device structure. * @param chx - Channel number. * @param settle_count - Settling time value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_settle_count(const struct device *dev, uint8_t chx, uint16_t settle_count) { return fdc2x1x_reg_write(dev, FDC2X1X_SETTLECOUNT_CH0 + chx, settle_count); } /** * Set the Reference Count value of a specific channel. * @param dev - The device structure. * @param chx - Channel number. * @param rcount - Reference count value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_rcount(const struct device *dev, uint8_t chx, uint16_t rcount) { return fdc2x1x_reg_write(dev, FDC2X1X_RCOUNT_CH0 + chx, rcount); } /** * Set the Offset value of a specific channel. * @param dev - The device structure. * @param chx - Channel number. * @param offset - Offset value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_offset(const struct device *dev, uint8_t chx, uint16_t offset) { return fdc2x1x_reg_write(dev, FDC2X1X_OFFSET_CH0 + chx, offset); } /** * Set the Auto-Scan Mode. * @param dev - The device structure. * @param en - Enable/disable auto-scan mode. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_autoscan_mode(const struct device *dev, bool en) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_MUX_CONFIG, FDC2X1X_MUX_CFG_AUTOSCAN_EN_MSK, FDC2X1X_MUX_CFG_AUTOSCAN_EN_SET(en)); } /** * Set the Auto-Scan Sequence Configuration. * @param dev - The device structure. * @param rr_seq - Auto-Scan sequence value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_rr_sequence(const struct device *dev, uint8_t rr_seq) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_MUX_CONFIG, FDC2X1X_MUX_CFG_RR_SEQUENCE_MSK, FDC2X1X_MUX_CFG_RR_SEQUENCE_SET(rr_seq)); } /** * Set the Input deglitch filter bandwidth. * @param dev - The device structure. * @param deglitch - Deglitch selection. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_deglitch(const struct device *dev, uint8_t deglitch) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_MUX_CONFIG, FDC2X1X_MUX_CFG_DEGLITCH_MSK, FDC2X1X_MUX_CFG_DEGLITCH_SET(deglitch)); } /** * Set the Output gain control. * @param dev - The device structure. * @param gain - Output gain. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_output_gain(const struct device *dev, uint8_t gain) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_RESET_DEV, FDC2X1X_RESET_DEV_OUTPUT_GAIN_MSK, FDC2X1X_RESET_DEV_OUTPUT_GAIN_SET(gain)); } /** * Set the Active Channel for single channel * conversion if Auto-Scan Mode is disabled. * @param dev - The device structure. * @param ch - Active channel. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_active_channel(const struct device *dev, uint8_t ch) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CONFIG, FDC2X1X_CFG_ACTIVE_CHAN_MSK, FDC2X1X_CFG_ACTIVE_CHAN_SET(ch)); } /** * Set the Sensor Activation Mode Selection. * @param dev - The device structure. * @param act_sel - Sensor Activation Mode Selection. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_sensor_activate_sel(const struct device *dev, uint8_t act_sel) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CONFIG, FDC2X1X_CFG_SENSOR_ACTIVATE_SEL_MSK, FDC2X1X_CFG_SENSOR_ACTIVATE_SEL_SET(act_sel)); } /** * Set the Reference Frequency Source. * @param dev - The device structure. * @param clk_src - Clock source. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_ref_clk_src(const struct device *dev, uint8_t clk_src) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CONFIG, FDC2X1X_CFG_REF_CLK_SRC_MSK, FDC2X1X_CFG_REF_CLK_SRC_SET(clk_src)); } /** * Set the Current Sensor Drive. * @param dev - The device structure. * @param cur_drv - Current Sensor Drive. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_current_drv(const struct device *dev, uint8_t cur_drv) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CONFIG, FDC2X1X_CFG_HIGH_CURRENT_DRV_MSK, FDC2X1X_CFG_HIGH_CURRENT_DRV_SET(cur_drv)); } /** * Enable/disable the INTB-Pin interrupt assertion. * @param dev - The device structure. * @param enable - True = enable int assertion, false = disable int assertion. * @return 0 in case of success, negative error code otherwise. */ int fdc2x1x_set_interrupt_pin(const struct device *dev, bool enable) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CONFIG, FDC2X1X_CFG_INTB_DIS_MSK, FDC2X1X_CFG_INTB_DIS_SET(!enable)); } /** * Set the Operation Mode * @param dev - The device structure. * @param op_mode - Operation mode * @return 0 in case of success, negative error code otherwise. */ int fdc2x1x_set_op_mode(const struct device *dev, enum fdc2x1x_op_mode op_mode) { return fdc2x1x_reg_write_mask(dev, FDC2X1X_CONFIG, FDC2X1X_CFG_SLEEP_SET_EN_MSK, FDC2X1X_CFG_SLEEP_SET_EN_SET(op_mode)); } /** * Get the STATUS register data * @param dev - The device structure. * @param status - Data stored in the STATUS register * @return 0 in case of success, negative error code otherwise. */ int fdc2x1x_get_status(const struct device *dev, uint16_t *status) { return fdc2x1x_reg_read(dev, FDC2X1X_STATUS, status); } /** * Reset the device. * @param dev - The device structure. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_reset(const struct device *dev) { int ret; ret = fdc2x1x_reg_write_mask(dev, FDC2X1X_RESET_DEV, FDC2X1X_RESET_DEV_MSK, FDC2X1X_RESET_DEV_SET(1)); return ret; } #ifdef CONFIG_PM_DEVICE /** * Reinitialize device after exiting shutdown mode * @param dev - The device structure. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_restart(const struct device *dev) { int ret; k_sleep(K_MSEC(100)); ret = fdc2x1x_init_config(dev); if (ret) { LOG_ERR("Reinitializing failed"); return ret; } #ifdef CONFIG_FDC2X1X_TRIGGER struct fdc2x1x_data *data = dev->data; ret = fdc2x1x_reg_write_mask(dev, FDC2X1X_ERROR_CONFIG, data->int_config, data->int_config); if (ret) { LOG_ERR("Reinitializing trigger failed"); return ret; } #endif return 0; } /** * Enable/disable Shutdown Mode * @param dev - The device structure. * @param enable - True = enable shutdown, false = disable shutdown * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_set_shutdown(const struct device *dev, bool enable) { const struct fdc2x1x_config *cfg = dev->config; int ret = 0; gpio_pin_set_dt(&cfg->sd_gpio, enable); if (!enable) { ret = fdc2x1x_restart(dev); } return ret; } /** * Set the Device Power Management State. * @param dev - The device structure. * @param pm_state - power management state * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_device_pm_action(const struct device *dev, enum pm_device_action action) { int ret; const struct fdc2x1x_config *cfg = dev->config; enum pm_device_state curr_state; (void)pm_device_state_get(dev, &curr_state); switch (action) { case PM_DEVICE_ACTION_RESUME: if (curr_state == PM_DEVICE_STATE_OFF) { ret = fdc2x1x_set_shutdown(dev, false); if (ret) { return ret; } } ret = fdc2x1x_set_op_mode(dev, FDC2X1X_ACTIVE_MODE); if (ret) { return ret; } break; case PM_DEVICE_ACTION_SUSPEND: if (curr_state == PM_DEVICE_STATE_OFF) { ret = fdc2x1x_set_shutdown(dev, false); if (ret) { return ret; } } ret = fdc2x1x_set_op_mode(dev, FDC2X1X_SLEEP_MODE); if (ret) { return ret; } break; case PM_DEVICE_ACTION_TURN_OFF: if (cfg->sd_gpio->port.name) { ret = fdc2x1x_set_shutdown(dev, true); } else { LOG_ERR("SD pin not defined"); ret = -ENOTSUP; } break; default: return -ENOTSUP; } return ret; } #endif /** * Set attributes for the device. * @param dev - The device structure. * @param chan - The sensor channel type. * @param attr - The sensor attribute. * @param value - The sensor attribute value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { return -ENOTSUP; } /** * Read sensor data from the device. * @param dev - The device structure. * @param cap_data - The sensor value data. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_get_cap_data(const struct device *dev) { uint8_t increment_steps; int i; const struct fdc2x1x_config *cfg = dev->config; struct fdc2x1x_data *data = dev->data; uint8_t reg_addr = FDC2X1X_DATA_CH0; uint8_t buf_size = cfg->num_channels; if (data->fdc221x) { buf_size *= 2; increment_steps = 1; } else { increment_steps = 2; } uint16_t buf[buf_size]; #ifdef CONFIG_FDC2X1X_TRIGGER_NONE uint16_t status; do { fdc2x1x_get_status(dev, &status); } while (!(FDC2X1X_STATUS_DRDY(status))); #endif for (i = 0; i < buf_size; i++) { if (fdc2x1x_reg_read(dev, reg_addr, &buf[i]) < 0) { LOG_ERR("Failed to read reg 0x%x", reg_addr); return -EIO; } reg_addr += increment_steps; } for (i = 0; i < cfg->num_channels; i++) { if (data->fdc221x) { data->channel_buf[i] = buf[i * 2] << 16 | buf[i * 2 + 1]; } else { data->channel_buf[i] = buf[i]; } } return 0; } /** * Fetch sensor data from the device. * @param dev - The device structure. * @param chan - The sensor channel type. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_sample_fetch(const struct device *dev, enum sensor_channel chan) { #ifdef CONFIG_PM_DEVICE enum pm_device_state state; (void)pm_device_state_get(dev, &state); if (state != PM_DEVICE_STATE_ACTIVE) { LOG_ERR("Sample fetch failed, device is not in active mode"); return -ENXIO; } #endif return fdc2x1x_get_cap_data(dev); } /** * Get sensor channel value from the device. * @param dev - The device structure. * @param chan - The sensor channel type. * @param val - The sensor channel value. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { const struct fdc2x1x_config *cfg = dev->config; double ch_data; switch ((int16_t)chan) { case SENSOR_CHAN_FDC2X1X_FREQ_CH0: fdc2x1x_raw_to_freq(dev, 0, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; break; case SENSOR_CHAN_FDC2X1X_FREQ_CH1: if (cfg->num_channels >= 2) { fdc2x1x_raw_to_freq(dev, 1, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; } else { LOG_ERR("CH1 not defined."); return -ENOTSUP; } break; case SENSOR_CHAN_FDC2X1X_FREQ_CH2: if (cfg->num_channels >= 3) { fdc2x1x_raw_to_freq(dev, 2, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; } else { LOG_ERR("CH2 not selected or not supported by device."); return -ENOTSUP; } break; case SENSOR_CHAN_FDC2X1X_FREQ_CH3: if (cfg->num_channels == 4) { fdc2x1x_raw_to_freq(dev, 3, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; } else { LOG_ERR("CH3 not selected or not supported by device."); return -ENOTSUP; } break; case SENSOR_CHAN_FDC2X1X_CAPACITANCE_CH0: fdc2x1x_raw_to_freq(dev, 0, &ch_data); fdc2x1x_raw_to_capacitance(dev, 0, ch_data, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; break; case SENSOR_CHAN_FDC2X1X_CAPACITANCE_CH1: if (cfg->num_channels >= 2) { fdc2x1x_raw_to_freq(dev, 1, &ch_data); fdc2x1x_raw_to_capacitance(dev, 1, ch_data, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; } else { LOG_ERR("CH1 not selected or not supported by device."); return -ENOTSUP; } break; case SENSOR_CHAN_FDC2X1X_CAPACITANCE_CH2: if (cfg->num_channels >= 3) { fdc2x1x_raw_to_freq(dev, 2, &ch_data); fdc2x1x_raw_to_capacitance(dev, 2, ch_data, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; } else { LOG_ERR("CH3 not selected or not supported by device."); return -ENOTSUP; } break; case SENSOR_CHAN_FDC2X1X_CAPACITANCE_CH3: if (cfg->num_channels >= 4) { fdc2x1x_raw_to_freq(dev, 3, &ch_data); fdc2x1x_raw_to_capacitance(dev, 3, ch_data, &ch_data); val->val1 = (uint32_t)ch_data; val->val2 = ((uint32_t)(ch_data * 1000000)) % 1000000; } else { LOG_ERR("CH3 not selected or not supported by device."); return -ENOTSUP; } break; default: LOG_ERR("Channel type not supported."); return -ENOTSUP; } return 0; } static const struct sensor_driver_api fdc2x1x_api_funcs = { .attr_set = fdc2x1x_attr_set, .sample_fetch = fdc2x1x_sample_fetch, .channel_get = fdc2x1x_channel_get, #ifdef CONFIG_FDC2X1X_TRIGGER .trigger_set = fdc2x1x_trigger_set, #endif }; static int fdc2x1x_init_config(const struct device *dev) { int ret; int ch; const struct fdc2x1x_config *cfg = dev->config; struct fdc2x1x_data *data = dev->data; /* Channel specific settings */ for (ch = 0; ch < cfg->num_channels; ch++) { ret = fdc2x1x_set_fin_sel(dev, ch, cfg->ch_cfg[ch].fin_sel); if (ret) { return ret; } ret = fdc2x1x_set_fref_divider(dev, ch, cfg->ch_cfg[ch].fref_divider); if (ret) { return ret; } ret = fdc2x1x_set_idrive(dev, ch, cfg->ch_cfg[ch].idrive); if (ret) { return ret; } ret = fdc2x1x_set_settle_count(dev, ch, cfg->ch_cfg[ch].settle_count); if (ret) { return ret; } ret = fdc2x1x_set_rcount(dev, ch, cfg->ch_cfg[ch].rcount); if (ret) { return ret; } if (!data->fdc221x) { ret = fdc2x1x_set_offset(dev, ch, cfg->ch_cfg[ch].offset); if (ret) { return ret; } } } ret = fdc2x1x_set_autoscan_mode(dev, cfg->autoscan_en); if (ret) { return ret; } ret = fdc2x1x_set_rr_sequence(dev, cfg->rr_sequence); if (ret) { return ret; } ret = fdc2x1x_set_deglitch(dev, cfg->deglitch); if (ret) { return ret; } if (!data->fdc221x) { ret = fdc2x1x_set_output_gain(dev, cfg->output_gain); if (ret) { return ret; } } ret = fdc2x1x_set_active_channel(dev, cfg->active_channel); if (ret) { return ret; } ret = fdc2x1x_set_sensor_activate_sel(dev, cfg->sensor_activate_sel); if (ret) { return ret; } ret = fdc2x1x_set_ref_clk_src(dev, cfg->clk_src); if (ret) { return ret; } #ifdef CONFIG_FDC2X1X_TRIGGER_NONE /* Enable Data Ready Flag to poll for new measurement */ ret = fdc2x1x_reg_write_mask(dev, FDC2X1X_ERROR_CONFIG, FDC2X1X_ERROR_CONFIG_DRDY_2INT_MSK, FDC2X1X_ERROR_CONFIG_DRDY_2INT_SET(1)); if (ret) { return ret; } /* INTB asserts by default, so disable it here */ ret = fdc2x1x_set_interrupt_pin(dev, false); if (ret) { return ret; } #endif ret = fdc2x1x_set_current_drv(dev, cfg->current_drv); if (ret) { return ret; } return 0; } /** * Probe device (Check if it is the correct device). * @param dev - The device structure. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_probe(const struct device *dev) { struct fdc2x1x_data *data = dev->data; uint16_t dev_id, man_id; if (fdc2x1x_reg_read(dev, FDC2X1X_DEVICE_ID, &dev_id) < 0) { LOG_ERR("Failed to read device id"); return -EIO; } if (dev_id == FDC2X1X_DEVICE_ID_VAL_28BIT) { data->fdc221x = true; } else if (dev_id == FDC2X1X_DEVICE_ID_VAL) { data->fdc221x = false; } else { LOG_ERR("Wrong device id"); return -ENODEV; } if (data->fdc221x) { printk("is 28bit\n"); } else { printk("is 12bit\n"); } if (fdc2x1x_reg_read(dev, FDC2X1X_MANUFACTURER_ID, &man_id) < 0) { LOG_ERR("Failed to read manufacturer id"); return -EIO; } if (man_id != FDC2X1X_MANUFACTURER_ID_VAL) { LOG_ERR("Wrong manufacturer id"); return -ENODEV; } return 0; } /** * Initialize the SD-Pin. * @param dev - The device structure. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_init_sd_pin(const struct device *dev) { const struct fdc2x1x_config *cfg = dev->config; if (!device_is_ready(cfg->sd_gpio.port)) { LOG_ERR("%s: sd_gpio device not ready", cfg->sd_gpio.port->name); return -ENODEV; } gpio_pin_configure_dt(&cfg->sd_gpio, GPIO_OUTPUT_INACTIVE); return 0; } /** * Initialization of the device. * @param dev - The device structure. * @return 0 in case of success, negative error code otherwise. */ static int fdc2x1x_init(const struct device *dev) { const struct fdc2x1x_config *cfg = dev->config; uint8_t ch_supported; if (cfg->fdc2x14) { ch_supported = 4; } else { ch_supported = 2; } if (cfg->num_channels == 0) { LOG_ERR("No channel nodes found"); return -EINVAL; } else if (cfg->num_channels > ch_supported) { LOG_ERR("Amount of channels not supported by this device"); return -EINVAL; } if (cfg->sd_gpio.port->name) { if (fdc2x1x_init_sd_pin(dev) < 0) { return -ENODEV; } } if (!device_is_ready(cfg->i2c.bus)) { LOG_ERR("I2C bus device not ready"); return -ENODEV; } if (fdc2x1x_probe(dev) < 0) { return -ENODEV; } if (fdc2x1x_reset(dev) < 0) { return -EIO; } if (fdc2x1x_init_config(dev) < 0) { return -EIO; } if (fdc2x1x_set_op_mode(dev, FDC2X1X_ACTIVE_MODE) < 0) { return -EIO; } #ifdef CONFIG_FDC2X1X_TRIGGER if (fdc2x1x_init_interrupt(dev) < 0) { LOG_ERR("Failed to initialize interrupt!"); return -EIO; } #endif return 0; } #define FDC2X1X_SD_PROPS(n) \ .sd_gpio = GPIO_DT_SPEC_INST_GET(n, sd_gpios), \ #define FDC2X1X_SD(n) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, sd_gpios), \ (FDC2X1X_SD_PROPS(n))) #define FDC2X1X_INTB_PROPS(n) \ .intb_gpio = GPIO_DT_SPEC_INST_GET(n, intb_gpios), \ #define FDC2X1X_INTB(n) \ IF_ENABLED(CONFIG_FDC2X1X_TRIGGER, \ (FDC2X1X_INTB_PROPS(n))) #define FDC2X1X_CH_CFG_INIT(ch) \ { \ .rcount = DT_PROP(ch, rcount), \ .offset = DT_PROP(ch, offset), \ .settle_count = DT_PROP(ch, settlecount), \ .fref_divider = DT_PROP(ch, fref_divider), \ .idrive = DT_PROP(ch, idrive), \ .fin_sel = DT_PROP(ch, fin_sel), \ .inductance = DT_PROP(ch, inductance), \ }, #define FDC2X1X_CHANNEL_BUF_INIT(ch) 0, #define FDC2X1X_INIT(n) \ static uint32_t fdc2x1x_sample_buf_##n[] = { \ DT_INST_FOREACH_CHILD(n, FDC2X1X_CHANNEL_BUF_INIT) \ }; \ \ static struct fdc2x1x_data fdc2x1x_data_##n = { \ .channel_buf = fdc2x1x_sample_buf_##n, \ }; \ \ const struct fdc2x1x_chx_config ch_cfg_##n[] = { \ DT_INST_FOREACH_CHILD(n, FDC2X1X_CH_CFG_INIT) \ }; \ \ static const struct fdc2x1x_config fdc2x1x_config_##n = { \ .i2c = I2C_DT_SPEC_INST_GET(n), \ .fdc2x14 = DT_INST_PROP(n, fdc2x14), \ .autoscan_en = DT_INST_PROP(n, autoscan), \ .rr_sequence = DT_INST_PROP(n, rr_sequence), \ .active_channel = DT_INST_PROP(n, active_channel), \ .deglitch = DT_INST_PROP(n, deglitch), \ .sensor_activate_sel = \ DT_INST_ENUM_IDX(n, sensor_activate_sel), \ .clk_src = DT_INST_ENUM_IDX(n, ref_clk_src), \ .current_drv = DT_INST_ENUM_IDX(n, current_drive), \ .output_gain = DT_INST_PROP(n, output_gain), \ .ch_cfg = ch_cfg_##n, \ .num_channels = ARRAY_SIZE(fdc2x1x_sample_buf_##n), \ .fref = DT_INST_PROP(n, fref), \ FDC2X1X_SD(n) \ FDC2X1X_INTB(n) \ }; \ \ PM_DEVICE_DT_INST_DEFINE(n, fdc2x1x_device_pm_action); \ \ DEVICE_DT_INST_DEFINE(n, \ fdc2x1x_init, \ PM_DEVICE_DT_INST_GET(n), \ &fdc2x1x_data_##n, \ &fdc2x1x_config_##n, \ POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, \ &fdc2x1x_api_funcs); DT_INST_FOREACH_STATUS_OKAY(FDC2X1X_INIT)