1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <device.h>
8 #include <drivers/gpio.h>
9 #include <sys/util.h>
10 #include <kernel.h>
11 #include <drivers/sensor.h>
12 
13 #include "bmc150_magn.h"
14 
15 #include <logging/log.h>
16 LOG_MODULE_DECLARE(BMC150_MAGN, CONFIG_SENSOR_LOG_LEVEL);
17 
setup_drdy(const struct device * dev,bool enable)18 static inline void setup_drdy(const struct device *dev,
19 			      bool enable)
20 {
21 	struct bmc150_magn_data *data = dev->data;
22 	const struct bmc150_magn_config *const cfg =
23 		dev->config;
24 
25 	gpio_pin_interrupt_configure(data->gpio_drdy,
26 				     cfg->gpio_drdy_int_pin,
27 				     enable
28 				     ? GPIO_INT_EDGE_TO_ACTIVE
29 				     : GPIO_INT_DISABLE);
30 }
31 
32 
bmc150_magn_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)33 int bmc150_magn_trigger_set(const struct device *dev,
34 			    const struct sensor_trigger *trig,
35 			    sensor_trigger_handler_t handler)
36 {
37 	struct bmc150_magn_data *data = dev->data;
38 	const struct bmc150_magn_config * const config =
39 					dev->config;
40 	uint8_t state;
41 
42 #if defined(CONFIG_BMC150_MAGN_TRIGGER_DRDY)
43 	if (trig->type == SENSOR_TRIG_DATA_READY) {
44 		setup_drdy(dev, false);
45 
46 		state = 0U;
47 		if (handler) {
48 			state = 1U;
49 		}
50 
51 		data->handler_drdy = handler;
52 		data->trigger_drdy = *trig;
53 
54 		if (i2c_reg_update_byte(data->i2c_master,
55 					config->i2c_slave_addr,
56 					BMC150_MAGN_REG_INT_DRDY,
57 					BMC150_MAGN_MASK_DRDY_EN,
58 					state << BMC150_MAGN_SHIFT_DRDY_EN)
59 					< 0) {
60 			LOG_DBG("failed to set DRDY interrupt");
61 			return -EIO;
62 		}
63 
64 		setup_drdy(dev, true);
65 	}
66 #endif
67 
68 	return 0;
69 }
70 
bmc150_magn_gpio_drdy_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)71 static void bmc150_magn_gpio_drdy_callback(const struct device *dev,
72 					   struct gpio_callback *cb,
73 					   uint32_t pins)
74 {
75 	struct bmc150_magn_data *data =
76 		CONTAINER_OF(cb, struct bmc150_magn_data, gpio_cb);
77 
78 	ARG_UNUSED(pins);
79 
80 	setup_drdy(data->dev, false);
81 
82 	k_sem_give(&data->sem);
83 }
84 
bmc150_magn_thread_main(struct bmc150_magn_data * data)85 static void bmc150_magn_thread_main(struct bmc150_magn_data *data)
86 {
87 	const struct bmc150_magn_config *config = data->dev->config;
88 	uint8_t reg_val;
89 
90 	while (1) {
91 		k_sem_take(&data->sem, K_FOREVER);
92 
93 		while (i2c_reg_read_byte(data->i2c_master,
94 					 config->i2c_slave_addr,
95 					 BMC150_MAGN_REG_INT_STATUS,
96 					 &reg_val) < 0) {
97 			LOG_DBG("failed to clear data ready interrupt");
98 		}
99 
100 		if (data->handler_drdy) {
101 			data->handler_drdy(data->dev, &data->trigger_drdy);
102 		}
103 
104 		setup_drdy(data->dev, true);
105 	}
106 }
107 
bmc150_magn_set_drdy_polarity(const struct device * dev,int state)108 static int bmc150_magn_set_drdy_polarity(const struct device *dev, int state)
109 {
110 	struct bmc150_magn_data *data = dev->data;
111 	const struct bmc150_magn_config *config = dev->config;
112 
113 	if (state) {
114 		state = 1;
115 	}
116 
117 	return i2c_reg_update_byte(data->i2c_master, config->i2c_slave_addr,
118 				   BMC150_MAGN_REG_INT_DRDY,
119 				   BMC150_MAGN_MASK_DRDY_DR_POLARITY,
120 				   state << BMC150_MAGN_SHIFT_DRDY_DR_POLARITY);
121 }
122 
bmc150_magn_init_interrupt(const struct device * dev)123 int bmc150_magn_init_interrupt(const struct device *dev)
124 {
125 	const struct bmc150_magn_config * const config =
126 						dev->config;
127 	struct bmc150_magn_data *data = dev->data;
128 
129 
130 #if defined(CONFIG_BMC150_MAGN_TRIGGER_DRDY)
131 	if (bmc150_magn_set_drdy_polarity(dev, 0) < 0) {
132 		LOG_DBG("failed to set DR polarity");
133 		return -EIO;
134 	}
135 
136 	if (i2c_reg_update_byte(data->i2c_master, config->i2c_slave_addr,
137 				BMC150_MAGN_REG_INT_DRDY,
138 				BMC150_MAGN_MASK_DRDY_EN,
139 				0 << BMC150_MAGN_SHIFT_DRDY_EN) < 0) {
140 		LOG_DBG("failed to set data ready interrupt enabled bit");
141 		return -EIO;
142 	}
143 #endif
144 
145 	data->handler_drdy = NULL;
146 
147 	k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
148 
149 	k_thread_create(&data->thread, data->thread_stack,
150 			CONFIG_BMC150_MAGN_TRIGGER_THREAD_STACK,
151 			(k_thread_entry_t)bmc150_magn_thread_main,
152 			data, NULL, NULL,
153 			K_PRIO_COOP(10), 0, K_NO_WAIT);
154 
155 	data->gpio_drdy = device_get_binding(config->gpio_drdy_dev_name);
156 	if (!data->gpio_drdy) {
157 		LOG_DBG("gpio controller %s not found",
158 			    config->gpio_drdy_dev_name);
159 		return -EINVAL;
160 	}
161 
162 	gpio_pin_configure(data->gpio_drdy, config->gpio_drdy_int_pin,
163 			   config->gpio_drdy_int_flags
164 			   | GPIO_INT_EDGE_TO_ACTIVE);
165 
166 	gpio_init_callback(&data->gpio_cb,
167 			   bmc150_magn_gpio_drdy_callback,
168 			   BIT(config->gpio_drdy_int_pin));
169 
170 	if (gpio_add_callback(data->gpio_drdy, &data->gpio_cb) < 0) {
171 		LOG_DBG("failed to set gpio callback");
172 		return -EIO;
173 	}
174 
175 	data->dev = dev;
176 
177 	return 0;
178 }
179