Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <adc.h>
#include <device.h>
#include <math.h>
#include <sensor.h>
#include <zephyr.h>

#define SYS_LOG_DOMAIN "GROVE_LIGHT_SENSOR"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_GROVE_LEVEL
#include <logging/sys_log.h>

struct gls_data {
	struct device *adc;
	struct adc_seq_entry sample;
	struct adc_seq_table adc_table;
	uint8_t adc_buffer[4];
};

static int gls_sample_fetch(struct device *dev, enum sensor_channel chan)
{
	struct gls_data *drv_data = dev->driver_data;

	return adc_read(drv_data->adc, &drv_data->adc_table);
}

static int gls_channel_get(struct device *dev,
			   enum sensor_channel chan,
			   struct sensor_value *val)
{
	struct gls_data *drv_data = dev->driver_data;
	uint16_t analog_val;
	double ldr_val, dval;

	/* rescale sample from 12bit (Zephyr) to 10bit (Grove) */
	analog_val = ((uint16_t)drv_data->adc_buffer[1] << 8) |
		     drv_data->adc_buffer[0];
	analog_val = analog_val >> 2;

	/*
	 * The formula for converting the analog value to lux is taken from
	 * the UPM project:
	 *     https://github.com/intel-iot-devkit/upm/blob/master/src/grove/grove.cxx#L161
	 */
	ldr_val = (1023.0 - analog_val) * 10.0 / analog_val;
	dval = 10000.0 / pow(ldr_val * 15.0, 4.0/3.0);

	val->val1 = (int32_t)dval;
	val->val2 = ((int32_t)(dval * 1000000)) % 1000000;

	return 0;
}

static const struct sensor_driver_api gls_api = {
	.sample_fetch = &gls_sample_fetch,
	.channel_get = &gls_channel_get,
};

static int gls_init(struct device *dev)
{
	struct gls_data *drv_data = dev->driver_data;

	drv_data->adc =
		device_get_binding(CONFIG_GROVE_LIGHT_SENSOR_ADC_DEV_NAME);
	if (drv_data->adc == NULL) {
		SYS_LOG_ERR("Failed to get ADC device.");
		return -EINVAL;
	}

	drv_data->sample.sampling_delay = 12;
	drv_data->sample.channel_id = CONFIG_GROVE_LIGHT_SENSOR_ADC_CHANNEL;
	drv_data->sample.buffer = drv_data->adc_buffer;
	drv_data->sample.buffer_length = 4;

	drv_data->adc_table.entries = &drv_data->sample;
	drv_data->adc_table.num_entries = 1;

	adc_enable(drv_data->adc);

	dev->driver_api = &gls_api;

	return 0;
}

static struct gls_data gls_data;

DEVICE_INIT(gls_dev, CONFIG_GROVE_LIGHT_SENSOR_NAME, &gls_init, &gls_data,
	    NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY);