Boot Linux faster!

Check our new training course

Boot Linux faster!

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

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2016 ARM Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <device.h>
#include <sensor.h>
#include <clock_control.h>

#define SYS_LOG_DOMAIN "TEMPNRF5"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
#include <logging/sys_log.h>

#include "nrf.h"
#include "nrf5_common.h"


/* The nRF5 temperature device returns measurements in 0.25C
 * increments.  Scale to mDegrees C.
 */
#define TEMP_NRF5_TEMP_SCALE (1000000 / 4)

struct temp_nrf5_data {
	struct k_sem device_sync_sem;
	s32_t sample;
	struct device *clk_m16_dev;
};


static int temp_nrf5_sample_fetch(struct device *dev, enum sensor_channel chan)
{
	volatile NRF_TEMP_Type *temp = NRF_TEMP;
	struct temp_nrf5_data *data = dev->driver_data;
	int r;

	SYS_LOG_DBG("");

	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_TEMP) {
		return -ENOTSUP;
	}

	/* The clock driver for nrf51 currently overloads the
	 * subsystem parameter with a flag to indicate whether or not
	 * it should block.
	 */
	r = clock_control_on(data->clk_m16_dev, (void *)1);
	__ASSERT_NO_MSG(!r);

	temp->TASKS_START = 1;
	k_sem_take(&data->device_sync_sem, K_FOREVER);

	r = clock_control_off(data->clk_m16_dev, (void *)1);
	__ASSERT_NO_MSG(!r);

	data->sample = temp->TEMP;

	temp->TASKS_STOP = 1;

	return 0;
}

static int temp_nrf5_channel_get(struct device *dev,
				enum sensor_channel chan,
				struct sensor_value *val)
{
	struct temp_nrf5_data *data = dev->driver_data;
	s32_t uval;

	SYS_LOG_DBG("");

	if (chan != SENSOR_CHAN_TEMP) {
		return -ENOTSUP;
	}

	uval = data->sample * TEMP_NRF5_TEMP_SCALE;
	val->val1 = uval / 1000000;
	val->val2 = uval % 1000000;

	return 0;
}

static void temp_nrf5_isr(void *arg)
{
	volatile NRF_TEMP_Type *temp = NRF_TEMP;
	struct device *dev = (struct device *)arg;
	struct temp_nrf5_data *data = dev->driver_data;

	temp->EVENTS_DATARDY = 0;
	k_sem_give(&data->device_sync_sem);
}

static const struct sensor_driver_api temp_nrf5_driver_api = {
	.sample_fetch = temp_nrf5_sample_fetch,
	.channel_get = temp_nrf5_channel_get,
};

static int temp_nrf5_init(struct device *dev);

static struct temp_nrf5_data temp_nrf5_driver;

DEVICE_AND_API_INIT(temp_nrf5, CONFIG_TEMP_NRF5_NAME, temp_nrf5_init,
		    &temp_nrf5_driver, NULL,
		    POST_KERNEL,
		    CONFIG_SENSOR_INIT_PRIORITY, &temp_nrf5_driver_api);

static int temp_nrf5_init(struct device *dev)
{
	volatile NRF_TEMP_Type *temp = NRF_TEMP;
	struct temp_nrf5_data *data = dev->driver_data;

	SYS_LOG_DBG("");

	data->clk_m16_dev =
		device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_M16SRC_DRV_NAME);
	__ASSERT_NO_MSG(data->clk_m16_dev);

	k_sem_init(&data->device_sync_sem, 0, UINT_MAX);
	IRQ_CONNECT(NRF5_IRQ_TEMP_IRQn, CONFIG_TEMP_NRF5_PRI,
		    temp_nrf5_isr, DEVICE_GET(temp_nrf5), 0);
	irq_enable(NRF5_IRQ_TEMP_IRQn);

	temp->INTENSET = TEMP_INTENSET_DATARDY_Set;

	return 0;
}