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 	if (channel_cfg->internal) {
89 		return -ENOTSUP;
90 	}
91 
92 	/* Enable Channel */
93 	dac->DACC_CHER = DACC_CHER_CH0 << channel_cfg->channel_id;
94 
95 	return 0;
96 }
97 
dac_sam_write_value(const struct device * dev,uint8_t channel,uint32_t value)98 static int dac_sam_write_value(const struct device *dev, uint8_t channel,
99 			       uint32_t value)
100 {
101 	struct dac_sam_dev_data *const dev_data = dev->data;
102 	const struct dac_sam_dev_cfg *const dev_cfg = dev->config;
103 	Dacc *const dac = dev_cfg->regs;
104 
105 	if (channel >= DAC_CHANNEL_NO) {
106 		return -EINVAL;
107 	}
108 
109 	if (dac->DACC_IMR & (DACC_IMR_TXRDY0 << channel)) {
110 		/* Attempting to send data on channel that's already in use */
111 		return -EINVAL;
112 	}
113 
114 	if (value >= BIT(12)) {
115 		LOG_ERR("value %d out of range", value);
116 		return -EINVAL;
117 	}
118 
119 	k_sem_take(&dev_data->dac_channels[channel].sem, K_FOREVER);
120 
121 	/* Trigger conversion */
122 	dac->DACC_CDR[channel] = DACC_CDR_DATA0(value);
123 
124 	/* Enable Transmit Ready Interrupt */
125 	dac->DACC_IER = DACC_IER_TXRDY0 << channel;
126 
127 	return 0;
128 }
129 
dac_sam_init(const struct device * dev)130 static int dac_sam_init(const struct device *dev)
131 {
132 	const struct dac_sam_dev_cfg *const dev_cfg = dev->config;
133 	struct dac_sam_dev_data *const dev_data = dev->data;
134 	Dacc *const dac = dev_cfg->regs;
135 	int retval;
136 
137 	/* Configure interrupts */
138 	dev_cfg->irq_config();
139 
140 	/* Initialize semaphores */
141 	for (int i = 0; i < ARRAY_SIZE(dev_data->dac_channels); i++) {
142 		k_sem_init(&dev_data->dac_channels[i].sem, 1, 1);
143 	}
144 
145 	/* Enable DAC clock in PMC */
146 	(void)clock_control_on(SAM_DT_PMC_CONTROLLER,
147 			       (clock_control_subsys_t)&dev_cfg->clock_cfg);
148 
149 	retval = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
150 	if (retval < 0) {
151 		return retval;
152 	}
153 
154 	/* Set Mode Register */
155 	dac->DACC_MR = DACC_MR_PRESCALER(dev_cfg->prescaler);
156 
157 	/* Enable module's IRQ */
158 	irq_enable(dev_cfg->irq_id);
159 
160 	LOG_INF("Device %s initialized", dev->name);
161 
162 	return 0;
163 }
164 
165 static DEVICE_API(dac, dac_sam_driver_api) = {
166 	.channel_setup = dac_sam_channel_setup,
167 	.write_value = dac_sam_write_value,
168 };
169 
170 /* DACC */
171 
dacc_irq_config(void)172 static void dacc_irq_config(void)
173 {
174 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), dac_sam_isr,
175 		    DEVICE_DT_INST_GET(0), 0);
176 }
177 
178 PINCTRL_DT_INST_DEFINE(0);
179 
180 static const struct dac_sam_dev_cfg dacc_sam_config = {
181 	.regs = (Dacc *)DT_INST_REG_ADDR(0),
182 	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
183 	.irq_id = DT_INST_IRQN(0),
184 	.irq_config = dacc_irq_config,
185 	.clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(0),
186 	.prescaler = DT_INST_PROP(0, prescaler),
187 };
188 
189 static struct dac_sam_dev_data dacc_sam_data;
190 
191 DEVICE_DT_INST_DEFINE(0, dac_sam_init, NULL, &dacc_sam_data, &dacc_sam_config,
192 		      POST_KERNEL, CONFIG_DAC_INIT_PRIORITY,
193 		      &dac_sam_driver_api);
194