1 /*
2 * Copyright (c) 2023 Michal Morsisko
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_tmag5170
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/pm/device.h>
13 #include <zephyr/logging/log.h>
14
15 #include "tmag5170.h"
16
17 LOG_MODULE_DECLARE(TMAG5170, CONFIG_SENSOR_LOG_LEVEL);
18
tmag5170_handle_interrupts(const void * arg)19 static void tmag5170_handle_interrupts(const void *arg)
20 {
21 const struct device *dev = (const struct device *)arg;
22 struct tmag5170_data *data = dev->data;
23
24 if (data->handler_drdy) {
25 data->handler_drdy(dev, data->trigger_drdy);
26 }
27 }
28
29 #if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
tmag5170_thread_main(void * arg1,void * unused1,void * unused2)30 static void tmag5170_thread_main(void *arg1, void *unused1, void *unused2)
31 {
32 ARG_UNUSED(unused1);
33 ARG_UNUSED(unused2);
34 const struct device *dev = (const struct device *)arg1;
35 struct tmag5170_data *data = dev->data;
36
37 while (1) {
38 k_sem_take(&data->sem, K_FOREVER);
39 tmag5170_handle_interrupts(dev);
40 }
41 }
42 #endif
43
44 #if defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
tmag5170_work_handler(struct k_work * work)45 static void tmag5170_work_handler(struct k_work *work)
46 {
47 struct tmag5170_data *data = CONTAINER_OF(work,
48 struct tmag5170_data,
49 work);
50
51 tmag5170_handle_interrupts(data->dev);
52 }
53 #endif
54
tmag5170_gpio_callback(const struct device * port,struct gpio_callback * cb,uint32_t pin)55 static void tmag5170_gpio_callback(const struct device *port,
56 struct gpio_callback *cb,
57 uint32_t pin)
58 {
59 struct tmag5170_data *data = CONTAINER_OF(cb,
60 struct tmag5170_data,
61 gpio_cb);
62
63 ARG_UNUSED(port);
64 ARG_UNUSED(pin);
65
66 #if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
67 k_sem_give(&data->sem);
68 #elif defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
69 k_work_submit(&data->work);
70 #elif defined(CONFIG_TMAG5170_TRIGGER_DIRECT)
71 tmag5170_handle_interrupts(data->dev);
72 #endif
73 }
74
tmag5170_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)75 int tmag5170_trigger_set(
76 const struct device *dev,
77 const struct sensor_trigger *trig,
78 sensor_trigger_handler_t handler)
79 {
80 struct tmag5170_data *data = dev->data;
81
82 #if defined(CONFIG_PM_DEVICE)
83 enum pm_device_state state;
84
85 (void)pm_device_state_get(dev, &state);
86 if (state != PM_DEVICE_STATE_ACTIVE) {
87 return -EBUSY;
88 }
89 #endif
90
91 if (trig->type != SENSOR_TRIG_DATA_READY) {
92 return -ENOTSUP;
93 }
94
95 data->trigger_drdy = trig;
96 data->handler_drdy = handler;
97
98 return 0;
99 }
100
tmag5170_trigger_init(const struct device * dev)101 int tmag5170_trigger_init(const struct device *dev)
102 {
103 struct tmag5170_data *data = dev->data;
104 const struct tmag5170_dev_config *cfg = dev->config;
105 int ret;
106
107 if (!device_is_ready(cfg->int_gpio.port)) {
108 LOG_ERR("%s: device %s is not ready", dev->name, cfg->int_gpio.port->name);
109 return -ENODEV;
110 }
111
112 data->dev = dev;
113
114 #if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
115 k_sem_init(&data->sem, 0, 1);
116 k_thread_create(
117 &data->thread,
118 data->thread_stack,
119 CONFIG_TMAG5170_THREAD_STACK_SIZE,
120 tmag5170_thread_main,
121 (void *)dev,
122 NULL,
123 NULL,
124 K_PRIO_COOP(CONFIG_TMAG5170_THREAD_PRIORITY),
125 0,
126 K_NO_WAIT);
127 #elif defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
128 data->work.handler = tmag5170_work_handler;
129 #endif
130 ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
131
132 if (ret < 0) {
133 return ret;
134 }
135
136 gpio_init_callback(&data->gpio_cb, tmag5170_gpio_callback, BIT(cfg->int_gpio.pin));
137
138 ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
139 if (ret < 0) {
140 return ret;
141 }
142
143 ret = gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_FALLING);
144 if (ret < 0) {
145 return ret;
146 }
147
148 return ret;
149 }
150