/* sensor_sx9500.c - Driver for Semtech SX9500 SAR proximity chip */ /* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT semtech_sx9500 #include #include #include #include #include #include #include #include #include "sx9500.h" LOG_MODULE_REGISTER(SX9500, CONFIG_SENSOR_LOG_LEVEL); static uint8_t sx9500_reg_defaults[] = { /* * First number is register address to write to. The chip * auto-increments the address for subsequent values in a single * write message. */ SX9500_REG_PROX_CTRL1, 0x43, /* Shield enabled, small range. */ 0x77, /* x8 gain, 167kHz frequency, finest resolution. */ 0x40, /* Doze enabled, 2x scan period doze, no raw filter. */ 0x30, /* Average threshold. */ 0x0f, /* Debouncer off, lowest average negative filter, * highest average positive filter. */ 0x0e, /* Proximity detection threshold: 280 */ 0x00, /* No automatic compensation, compensate each pin * independently, proximity hysteresis: 32, close * debouncer off, far debouncer off. */ 0x00, /* No stuck timeout, no periodic compensation. */ }; static int sx9500_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct sx9500_data *data = dev->data; const struct sx9500_config *cfg = dev->config; __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_PROX); return i2c_reg_read_byte_dt(&cfg->i2c, SX9500_REG_STAT, &data->prox_stat); } static int sx9500_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct sx9500_data *data = (struct sx9500_data *) dev->data; __ASSERT_NO_MSG(chan == SENSOR_CHAN_PROX); if (chan != SENSOR_CHAN_PROX) { return -ENOTSUP; } val->val1 = !!(data->prox_stat & (1 << (4 + CONFIG_SX9500_PROX_CHANNEL))); val->val2 = 0; return 0; } static DEVICE_API(sensor, sx9500_api_funcs) = { .sample_fetch = sx9500_sample_fetch, .channel_get = sx9500_channel_get, #ifdef CONFIG_SX9500_TRIGGER .trigger_set = sx9500_trigger_set, #endif }; static int sx9500_init_chip(const struct device *dev) { const struct sx9500_config *cfg = dev->config; uint8_t val; if (i2c_write_dt(&cfg->i2c, sx9500_reg_defaults, sizeof(sx9500_reg_defaults)) < 0) { return -EIO; } /* No interrupts active. We only activate them when an * application registers a trigger. */ if (i2c_reg_write_byte_dt(&cfg->i2c, SX9500_REG_IRQ_MSK, 0) < 0) { return -EIO; } /* Read irq source reg to clear reset status. */ if (i2c_reg_read_byte_dt(&cfg->i2c, SX9500_REG_IRQ_SRC, &val) < 0) { return -EIO; } return i2c_reg_write_byte_dt(&cfg->i2c, SX9500_REG_PROX_CTRL0, 1 << CONFIG_SX9500_PROX_CHANNEL); } int sx9500_init(const struct device *dev) { const struct sx9500_config *cfg = dev->config; if (!device_is_ready(cfg->i2c.bus)) { LOG_ERR("Bus device is not ready"); return -ENODEV; } if (sx9500_init_chip(dev) < 0) { LOG_DBG("sx9500: failed to initialize chip"); return -EINVAL; } #ifdef CONFIG_SX9500_TRIGGER if (cfg->int_gpio.port) { if (sx9500_setup_interrupt(dev) < 0) { LOG_DBG("sx9500: failed to setup interrupt"); return -EINVAL; } } #endif return 0; } #define SX9500_DEFINE(inst) \ struct sx9500_data sx9500_data_##inst; \ \ static const struct sx9500_config sx9500_config_##inst = { \ .i2c = I2C_DT_SPEC_INST_GET(inst), \ IF_ENABLED(CONFIG_SX9500_TRIGGER, \ (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, { 0 }),)) \ }; \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, sx9500_init, NULL, \ &sx9500_data_##inst, &sx9500_config_##inst, POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, &sx9500_api_funcs); \ DT_INST_FOREACH_STATUS_OKAY(SX9500_DEFINE)