1111#include <zephyr/drivers/adc.h>
1212#include <zephyr/logging/log.h>
1313#include <zephyr/drivers/i2c.h>
14+ #include <zephyr/drivers/gpio.h>
1415#include <zephyr/kernel.h>
1516#include <zephyr/sys/byteorder.h>
1617#include <zephyr/sys/util.h>
2021
2122LOG_MODULE_REGISTER (ADS1X1X , CONFIG_ADC_LOG_LEVEL );
2223
24+ #if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY (ti_ads1115 , alert_rdy_gpios ) || \
25+ DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY (ti_ads1114 , alert_rdy_gpios ) || \
26+ DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY (ti_ads1015 , alert_rdy_gpios ) || \
27+ DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY (ti_ads1014 , alert_rdy_gpios )
28+
29+ #define ADC_ADS1X1X_TRIGGER
30+
31+ #endif
32+
2333#define ADS1X1X_CONFIG_OS BIT(15)
2434#define ADS1X1X_CONFIG_MUX (x ) ((x) << 12)
2535#define ADS1X1X_CONFIG_PGA (x ) ((x) << 9)
@@ -29,6 +39,7 @@ LOG_MODULE_REGISTER(ADS1X1X, CONFIG_ADC_LOG_LEVEL);
2939#define ADS1X1X_CONFIG_COMP_POL BIT(3)
3040#define ADS1X1X_CONFIG_COMP_LAT BIT(2)
3141#define ADS1X1X_CONFIG_COMP_QUE (x ) (x)
42+ #define ADS1X1X_THRES_POLARITY_ACTIVE BIT(15)
3243
3344enum ads1x1x_reg {
3445 ADS1X1X_REG_CONV = 0x00 ,
@@ -124,6 +135,9 @@ enum {
124135
125136struct ads1x1x_config {
126137 struct i2c_dt_spec bus ;
138+ #ifdef ADC_ADS1X1X_TRIGGER
139+ struct gpio_dt_spec alert_rdy ;
140+ #endif
127141 const uint32_t odr_delay [8 ];
128142 uint8_t resolution ;
129143 bool multiplexer ;
@@ -138,11 +152,48 @@ struct ads1x1x_data {
138152 int16_t * buffer ;
139153 int16_t * repeat_buffer ;
140154 struct k_thread thread ;
155+ k_tid_t tid ;
141156 bool differential ;
157+ #ifdef ADC_ADS1X1X_TRIGGER
158+ struct gpio_callback gpio_cb ;
159+ struct k_work work ;
160+ #endif
142161
143162 K_KERNEL_STACK_MEMBER (stack , CONFIG_ADC_ADS1X1X_ACQUISITION_THREAD_STACK_SIZE );
144163};
145164
165+ #ifdef ADC_ADS1X1X_TRIGGER
166+ static inline int ads1x1x_setup_rdy_pin (const struct device * dev , bool enable )
167+ {
168+ int ret ;
169+ const struct ads1x1x_config * config = dev -> config ;
170+ gpio_flags_t flags = enable
171+ ? GPIO_INPUT | config -> alert_rdy .dt_flags
172+ : GPIO_DISCONNECTED ;
173+
174+ ret = gpio_pin_configure_dt (& config -> alert_rdy , flags );
175+ if (ret < 0 ) {
176+ LOG_DBG ("Could not configure gpio" );
177+ }
178+ return ret ;
179+ }
180+
181+ static inline int ads1x1x_setup_rdy_interrupt (const struct device * dev , bool enable )
182+ {
183+ const struct ads1x1x_config * config = dev -> config ;
184+ gpio_flags_t flags = enable
185+ ? GPIO_INT_EDGE_FALLING
186+ : GPIO_INT_DISABLE ;
187+ int32_t ret ;
188+
189+ ret = gpio_pin_interrupt_configure_dt (& config -> alert_rdy , flags );
190+ if (ret < 0 ) {
191+ LOG_DBG ("Could not configure GPIO" );
192+ }
193+ return ret ;
194+ }
195+ #endif
196+
146197static int ads1x1x_read_reg (const struct device * dev , enum ads1x1x_reg reg_addr , uint16_t * buf )
147198{
148199 const struct ads1x1x_config * config = dev -> config ;
@@ -197,6 +248,40 @@ static int ads1x1x_start_conversion(const struct device *dev)
197248 return ret ;
198249}
199250
251+ #ifdef ADC_ADS1X1X_TRIGGER
252+ /* The ALERT/RDY pin can also be configured as a conversion ready
253+ * pin. Set the most-significant bit of the Hi_thresh register to 1
254+ * and the most-significant bit of Lo_thresh register to 0 to enable
255+ * the pin as a conversion ready pin
256+ */
257+ static int ads1x1x_enable_conv_ready_signal (const struct device * dev )
258+ {
259+ uint16_t thresh ;
260+ int rc ;
261+
262+ /* set to 1 to enable conversion ALERT/RDY */
263+ rc = ads1x1x_read_reg (dev , ADS1X1X_REG_HI_THRESH , & thresh );
264+ if (rc ) {
265+ return rc ;
266+ }
267+ thresh |= ADS1X1X_THRES_POLARITY_ACTIVE ;
268+ rc = ads1x1x_write_reg (dev , ADS1X1X_REG_HI_THRESH , thresh );
269+ if (rc ) {
270+ return rc ;
271+ }
272+
273+ /* set to 0 to enable conversion ALERT/RDY */
274+ rc = ads1x1x_read_reg (dev , ADS1X1X_REG_LO_THRESH , & thresh );
275+ if (rc ) {
276+ return rc ;
277+ }
278+ thresh &= ~ADS1X1X_THRES_POLARITY_ACTIVE ;
279+ rc = ads1x1x_write_reg (dev , ADS1X1X_REG_LO_THRESH , thresh );
280+
281+ return rc ;
282+ }
283+ #endif
284+
200285static inline int ads1x1x_acq_time_to_dr (const struct device * dev , uint16_t acq_time )
201286{
202287 struct ads1x1x_data * data = dev -> data ;
@@ -475,7 +560,11 @@ static void adc_context_start_sampling(struct adc_context *ctx)
475560 adc_context_complete (ctx , ret );
476561 return ;
477562 }
478- k_sem_give (& data -> acq_sem );
563+
564+ /* Give semaphore only if the thread is running */
565+ if (data -> tid ) {
566+ k_sem_give (& data -> acq_sem );
567+ }
479568}
480569
481570static int ads1x1x_adc_start_read (const struct device * dev , const struct adc_sequence * sequence )
@@ -490,6 +579,23 @@ static int ads1x1x_adc_start_read(const struct device *dev, const struct adc_seq
490579
491580 data -> buffer = sequence -> buffer ;
492581
582+ #ifdef ADC_ADS1X1X_TRIGGER
583+ const struct ads1x1x_config * config = dev -> config ;
584+
585+ if (config -> alert_rdy .port ) {
586+ rc = ads1x1x_setup_rdy_pin (dev , true);
587+ if (rc < 0 ) {
588+ LOG_ERR ("Could not configure GPIO Alert/RDY" );
589+ return rc ;
590+ }
591+ rc = ads1x1x_setup_rdy_interrupt (dev , true);
592+ if (rc < 0 ) {
593+ LOG_ERR ("Could not configure Alert/RDY interrupt" );
594+ return rc ;
595+ }
596+ }
597+ #endif
598+
493599 adc_context_start_read (& data -> ctx , sequence );
494600
495601 return adc_context_wait_for_completion (& data -> ctx );
@@ -560,6 +666,86 @@ static void ads1x1x_acquisition_thread(void *p1, void *p2, void *p3)
560666 }
561667}
562668
669+ #ifdef ADC_ADS1X1X_TRIGGER
670+ static void ads1x1x_work_fn (struct k_work * work )
671+ {
672+ struct ads1x1x_data * data ;
673+ const struct device * dev ;
674+
675+ data = CONTAINER_OF (work , struct ads1x1x_data , work );
676+ dev = data -> dev ;
677+
678+ ads1x1x_adc_perform_read (dev );
679+ }
680+
681+ static void ads1x1x_conv_ready_cb (const struct device * gpio_dev ,
682+ struct gpio_callback * cb ,
683+ uint32_t pins )
684+ {
685+ struct ads1x1x_data * data ;
686+ const struct device * dev ;
687+ const struct ads1x1x_config * config ;
688+ int rc ;
689+
690+ ARG_UNUSED (gpio_dev );
691+
692+ data = CONTAINER_OF (cb , struct ads1x1x_data , gpio_cb );
693+ dev = data -> dev ;
694+ config = dev -> config ;
695+
696+ if (config -> alert_rdy .port ) {
697+ rc = ads1x1x_setup_rdy_pin (dev , false);
698+ if (rc < 0 ) {
699+ return ;
700+ }
701+ rc = ads1x1x_setup_rdy_interrupt (dev , false);
702+ if (rc < 0 ) {
703+ return ;
704+ }
705+ }
706+
707+ /* Execute outside of the ISR context */
708+ k_work_submit (& data -> work );
709+ }
710+
711+ static int ads1x1x_init_interrupt (const struct device * dev )
712+ {
713+ const struct ads1x1x_config * config = dev -> config ;
714+ struct ads1x1x_data * data = dev -> data ;
715+ int rc ;
716+
717+ /* Disable the interrupt */
718+ rc = ads1x1x_setup_rdy_pin (dev , false);
719+ if (rc < 0 ) {
720+ LOG_ERR ("Could disable the alert/rdy gpio pin." );
721+ return rc ;
722+ }
723+ rc = ads1x1x_setup_rdy_interrupt (dev , false);
724+ if (rc < 0 ) {
725+ LOG_ERR ("Could disable the alert/rdy interrupts." );
726+ return rc ;
727+ }
728+ gpio_init_callback (& data -> gpio_cb , ads1x1x_conv_ready_cb ,
729+ BIT (config -> alert_rdy .pin ));
730+ rc = gpio_add_callback (config -> alert_rdy .port , & data -> gpio_cb );
731+ if (rc ) {
732+ LOG_ERR ("Could not set gpio callback." );
733+ return - rc ;
734+ }
735+
736+ /* Use the interruption generated by the pin RDY */
737+ k_work_init (& data -> work , ads1x1x_work_fn );
738+
739+ rc = ads1x1x_enable_conv_ready_signal (dev );
740+ if (rc ) {
741+ LOG_ERR ("failed to configure ALERT/RDY pin (err=%d)" , rc );
742+ return rc ;
743+ }
744+
745+ return 0 ;
746+ }
747+ #endif
748+
563749static int ads1x1x_init (const struct device * dev )
564750{
565751 const struct ads1x1x_config * config = dev -> config ;
@@ -574,11 +760,26 @@ static int ads1x1x_init(const struct device *dev)
574760 return - ENODEV ;
575761 }
576762
577- k_tid_t tid =
578- k_thread_create (& data -> thread , data -> stack , K_THREAD_STACK_SIZEOF (data -> stack ),
579- ads1x1x_acquisition_thread , (void * )dev , NULL ,
580- NULL , CONFIG_ADC_ADS1X1X_ACQUISITION_THREAD_PRIO , 0 , K_NO_WAIT );
581- k_thread_name_set (tid , "adc_ads1x1x" );
763+ #ifdef ADC_ADS1X1X_TRIGGER
764+ if (config -> alert_rdy .port ) {
765+ if (ads1x1x_init_interrupt (dev ) < 0 ) {
766+ LOG_ERR ("Failed to initialize interrupt." );
767+ return - EIO ;
768+ }
769+ } else
770+ #endif
771+ {
772+ LOG_DBG ("Using acquisition thread" );
773+
774+ data -> tid =
775+ k_thread_create (& data -> thread , data -> stack ,
776+ K_THREAD_STACK_SIZEOF (data -> stack ),
777+ (k_thread_entry_t )ads1x1x_acquisition_thread ,
778+ (void * )dev , NULL , NULL ,
779+ CONFIG_ADC_ADS1X1X_ACQUISITION_THREAD_PRIO ,
780+ 0 , K_NO_WAIT );
781+ k_thread_name_set (data -> tid , "adc_ads1x1x" );
782+ }
582783
583784 adc_context_unlock_unconditionally (& data -> ctx );
584785
@@ -596,13 +797,21 @@ static const struct adc_driver_api ads1x1x_api = {
596797
597798#define DT_INST_ADS1X1X (inst , t ) DT_INST(inst, ti_ads##t)
598799
800+ #define ADS1X1X_RDY_PROPS (n ) \
801+ .alert_rdy = GPIO_DT_SPEC_INST_GET_OR(n, alert_rdy_gpios, {0}), \
802+
803+ #define ADS1X1X_RDY (t , n ) \
804+ IF_ENABLED(DT_NODE_HAS_PROP(DT_INST_ADS1X1X(n, t), alert_rdy_gpios), \
805+ (ADS1X1X_RDY_PROPS(n)))
806+
599807#define ADS1X1X_INIT (t , n , odr_delay_us , res , mux , pgab ) \
600808 static const struct ads1x1x_config ads##t##_config_##n = { \
601809 .bus = I2C_DT_SPEC_GET(DT_INST_ADS1X1X(n, t)), \
602810 .odr_delay = odr_delay_us, \
603811 .resolution = res, \
604812 .multiplexer = mux, \
605813 .pga = pgab, \
814+ IF_ENABLED(ADC_ADS1X1X_TRIGGER, (ADS1X1X_RDY(t, n))) \
606815 }; \
607816 static struct ads1x1x_data ads##t##_data_##n = { \
608817 ADC_CONTEXT_INIT_LOCK(ads##t##_data_##n, ctx), \
0 commit comments