/* sensor_sx9500.c - Driver for Semtech SX9500 SAR proximity chip */ /* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include "sx9500.h" static u8_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 postive 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(struct device *dev, enum sensor_channel chan) { struct sx9500_data *data = (struct sx9500_data *) dev->driver_data; __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_PROX); return i2c_reg_read_byte(data->i2c_master, data->i2c_slave_addr, SX9500_REG_STAT, &data->prox_stat); } static int sx9500_channel_get(struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct sx9500_data *data = (struct sx9500_data *) dev->driver_data; __ASSERT_NO_MSG(chan == SENSOR_CHAN_PROX); val->val1 = !!(data->prox_stat & (1 << (4 + CONFIG_SX9500_PROX_CHANNEL))); val->val2 = 0; return 0; } static const struct sensor_driver_api 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(struct device *dev) { struct sx9500_data *data = (struct sx9500_data *) dev->driver_data; u8_t val; if (i2c_write(data->i2c_master, sx9500_reg_defaults, sizeof(sx9500_reg_defaults), data->i2c_slave_addr) < 0) { return -EIO; } /* No interrupts active. We only activate them when an * application registers a trigger. */ if (i2c_reg_write_byte(data->i2c_master, data->i2c_slave_addr, SX9500_REG_IRQ_MSK, 0) < 0) { return -EIO; } /* Read irq source reg to clear reset status. */ if (i2c_reg_read_byte(data->i2c_master, data->i2c_slave_addr, SX9500_REG_IRQ_SRC, &val) < 0) { return -EIO; } return i2c_reg_write_byte(data->i2c_master, data->i2c_slave_addr, SX9500_REG_PROX_CTRL0, 1 << CONFIG_SX9500_PROX_CHANNEL); } int sx9500_init(struct device *dev) { struct sx9500_data *data = dev->driver_data; data->i2c_master = device_get_binding(CONFIG_SX9500_I2C_DEV_NAME); if (!data->i2c_master) { SYS_LOG_DBG("sx9500: i2c master not found: %s", CONFIG_SX9500_I2C_DEV_NAME); return -EINVAL; } data->i2c_slave_addr = CONFIG_SX9500_I2C_ADDR; if (sx9500_init_chip(dev) < 0) { SYS_LOG_DBG("sx9500: failed to initialize chip"); return -EINVAL; } if (sx9500_setup_interrupt(dev) < 0) { SYS_LOG_DBG("sx9500: failed to setup interrupt"); return -EINVAL; } dev->driver_api = &sx9500_api_funcs; return 0; } struct sx9500_data sx9500_data; DEVICE_INIT(sx9500, CONFIG_SX9500_DEV_NAME, sx9500_init, &sx9500_data, NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY);