1 /*
2 * Copyright (c) 2021 Piotr Mienkowski
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 /** @file
7 * @brief DAC driver for Atmel SAM MCU family.
8 *
9 * Remarks:
10 * Only SAME70, SAMV71 series devices are currently supported. Please submit a
11 * patch.
12 */
13
14 #define DT_DRV_COMPAT atmel_sam_dac
15
16 #include <errno.h>
17 #include <zephyr/sys/__assert.h>
18 #include <soc.h>
19 #include <zephyr/device.h>
20 #include <zephyr/drivers/dac.h>
21 #include <zephyr/drivers/pinctrl.h>
22 #include <zephyr/drivers/clock_control/atmel_sam_pmc.h>
23 #include <zephyr/kernel.h>
24 #include <zephyr/logging/log.h>
25 #include <zephyr/irq.h>
26 LOG_MODULE_REGISTER(dac_sam, CONFIG_DAC_LOG_LEVEL);
27
28 BUILD_ASSERT(IS_ENABLED(CONFIG_SOC_SERIES_SAME70) ||
29 IS_ENABLED(CONFIG_SOC_SERIES_SAMV71),
30 "Only SAME70, SAMV71 series devices are currently supported.");
31
32 #define DAC_CHANNEL_NO 2
33
34 /* Device constant configuration parameters */
35 struct dac_sam_dev_cfg {
36 Dacc *regs;
37 const struct atmel_sam_pmc_config clock_cfg;
38 const struct pinctrl_dev_config *pcfg;
39 void (*irq_config)(void);
40 uint8_t irq_id;
41 uint8_t prescaler;
42 };
43
44 struct dac_channel {
45 struct k_sem sem;
46 };
47
48 /* Device run time data */
49 struct dac_sam_dev_data {
50 struct dac_channel dac_channels[DAC_CHANNEL_NO];
51 };
52
dac_sam_isr(const struct device * dev)53 static void dac_sam_isr(const struct device *dev)
54 {
55 const struct dac_sam_dev_cfg *const dev_cfg = dev->config;
56 struct dac_sam_dev_data *const dev_data = dev->data;
57 Dacc *const dac = dev_cfg->regs;
58 uint32_t int_stat;
59
60 /* Retrieve interrupt status */
61 int_stat = dac->DACC_ISR & dac->DACC_IMR;
62
63 if ((int_stat & DACC_ISR_TXRDY0) != 0) {
64 /* Disable Transmit Ready Interrupt */
65 dac->DACC_IDR = DACC_IDR_TXRDY0;
66 k_sem_give(&dev_data->dac_channels[0].sem);
67 }
68 if ((int_stat & DACC_ISR_TXRDY1) != 0) {
69 /* Disable Transmit Ready Interrupt */
70 dac->DACC_IDR = DACC_IDR_TXRDY1;
71 k_sem_give(&dev_data->dac_channels[1].sem);
72 }
73 }
74
dac_sam_channel_setup(const struct device * dev,const struct dac_channel_cfg * channel_cfg)75 static int dac_sam_channel_setup(const struct device *dev,
76 const struct dac_channel_cfg *channel_cfg)
77 {
78 const struct dac_sam_dev_cfg *const dev_cfg = dev->config;
79 Dacc *const dac = dev_cfg->regs;
80
81 if (channel_cfg->channel_id >= DAC_CHANNEL_NO) {
82 return -EINVAL;
83 }
84 if (channel_cfg->resolution != 12) {
85 return -ENOTSUP;
86 }
87
88 /* Enable Channel */
89 dac->DACC_CHER = DACC_CHER_CH0 << channel_cfg->channel_id;
90
91 return 0;
92 }
93
dac_sam_write_value(const struct device * dev,uint8_t channel,uint32_t value)94 static int dac_sam_write_value(const struct device *dev, uint8_t channel,
95 uint32_t value)
96 {
97 struct dac_sam_dev_data *const dev_data = dev->data;
98 const struct dac_sam_dev_cfg *const dev_cfg = dev->config;
99 Dacc *const dac = dev_cfg->regs;
100
101 if (channel >= DAC_CHANNEL_NO) {
102 return -EINVAL;
103 }
104
105 if (dac->DACC_IMR & (DACC_IMR_TXRDY0 << channel)) {
106 /* Attempting to send data on channel that's already in use */
107 return -EINVAL;
108 }
109
110 k_sem_take(&dev_data->dac_channels[channel].sem, K_FOREVER);
111
112 /* Trigger conversion */
113 dac->DACC_CDR[channel] = DACC_CDR_DATA0(value);
114
115 /* Enable Transmit Ready Interrupt */
116 dac->DACC_IER = DACC_IER_TXRDY0 << channel;
117
118 return 0;
119 }
120
dac_sam_init(const struct device * dev)121 static int dac_sam_init(const struct device *dev)
122 {
123 const struct dac_sam_dev_cfg *const dev_cfg = dev->config;
124 struct dac_sam_dev_data *const dev_data = dev->data;
125 Dacc *const dac = dev_cfg->regs;
126 int retval;
127
128 /* Configure interrupts */
129 dev_cfg->irq_config();
130
131 /* Initialize semaphores */
132 for (int i = 0; i < ARRAY_SIZE(dev_data->dac_channels); i++) {
133 k_sem_init(&dev_data->dac_channels[i].sem, 1, 1);
134 }
135
136 /* Enable DAC clock in PMC */
137 (void)clock_control_on(SAM_DT_PMC_CONTROLLER,
138 (clock_control_subsys_t)&dev_cfg->clock_cfg);
139
140 retval = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
141 if (retval < 0) {
142 return retval;
143 }
144
145 /* Set Mode Register */
146 dac->DACC_MR = DACC_MR_PRESCALER(dev_cfg->prescaler);
147
148 /* Enable module's IRQ */
149 irq_enable(dev_cfg->irq_id);
150
151 LOG_INF("Device %s initialized", dev->name);
152
153 return 0;
154 }
155
156 static const struct dac_driver_api dac_sam_driver_api = {
157 .channel_setup = dac_sam_channel_setup,
158 .write_value = dac_sam_write_value,
159 };
160
161 /* DACC */
162
dacc_irq_config(void)163 static void dacc_irq_config(void)
164 {
165 IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), dac_sam_isr,
166 DEVICE_DT_INST_GET(0), 0);
167 }
168
169 PINCTRL_DT_INST_DEFINE(0);
170
171 static const struct dac_sam_dev_cfg dacc_sam_config = {
172 .regs = (Dacc *)DT_INST_REG_ADDR(0),
173 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
174 .irq_id = DT_INST_IRQN(0),
175 .irq_config = dacc_irq_config,
176 .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(0),
177 .prescaler = DT_INST_PROP(0, prescaler),
178 };
179
180 static struct dac_sam_dev_data dacc_sam_data;
181
182 DEVICE_DT_INST_DEFINE(0, dac_sam_init, NULL, &dacc_sam_data, &dacc_sam_config,
183 POST_KERNEL, CONFIG_DAC_INIT_PRIORITY,
184 &dac_sam_driver_api);
185