1 /*
2  * Copyright (c) 2023 Gerson Fernando Budke <nandojve@gmail.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT atmel_sam_pmc
8 
9 #include <stdint.h>
10 
11 #include <zephyr/arch/cpu.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/drivers/clock_control.h>
15 #include <zephyr/drivers/clock_control/atmel_sam_pmc.h>
16 #include <soc.h>
17 
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
20 
atmel_sam_clock_control_on(const struct device * dev,clock_control_subsys_t sys)21 static int atmel_sam_clock_control_on(const struct device *dev,
22 				      clock_control_subsys_t sys)
23 {
24 	ARG_UNUSED(dev);
25 
26 	const struct atmel_sam_pmc_config *cfg = (const struct atmel_sam_pmc_config *)sys;
27 
28 	if (cfg == NULL) {
29 		LOG_ERR("The PMC config can not be NULL.");
30 		return -ENXIO;
31 	}
32 
33 	LOG_DBG("Type: %x, Id: %d", cfg->clock_type, cfg->peripheral_id);
34 
35 	switch (cfg->clock_type) {
36 	case PMC_TYPE_PERIPHERAL:
37 		soc_pmc_peripheral_enable(cfg->peripheral_id);
38 		break;
39 	default:
40 		LOG_ERR("The PMC clock type is not implemented.");
41 		return -ENODEV;
42 	}
43 
44 	return 0;
45 }
46 
atmel_sam_clock_control_off(const struct device * dev,clock_control_subsys_t sys)47 static int atmel_sam_clock_control_off(const struct device *dev,
48 				       clock_control_subsys_t sys)
49 {
50 	ARG_UNUSED(dev);
51 
52 	const struct atmel_sam_pmc_config *cfg = (const struct atmel_sam_pmc_config *)sys;
53 
54 	if (cfg == NULL) {
55 		LOG_ERR("The PMC config can not be NULL.");
56 		return -ENXIO;
57 	}
58 
59 	LOG_DBG("Type: %x, Id: %d", cfg->clock_type, cfg->peripheral_id);
60 
61 	switch (cfg->clock_type) {
62 	case PMC_TYPE_PERIPHERAL:
63 		soc_pmc_peripheral_disable(cfg->peripheral_id);
64 		break;
65 	default:
66 		LOG_ERR("The PMC clock type is not implemented.");
67 		return -ENODEV;
68 	}
69 
70 	return 0;
71 }
72 
atmel_sam_clock_control_get_rate(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)73 static int atmel_sam_clock_control_get_rate(const struct device *dev,
74 					    clock_control_subsys_t sys,
75 					    uint32_t *rate)
76 {
77 	ARG_UNUSED(dev);
78 
79 	const struct atmel_sam_pmc_config *cfg = (const struct atmel_sam_pmc_config *)sys;
80 
81 	if (cfg == NULL) {
82 		LOG_ERR("The PMC config can not be NULL.");
83 		return -ENXIO;
84 	}
85 
86 	LOG_DBG("Type: %x, Id: %d", cfg->clock_type, cfg->peripheral_id);
87 
88 	switch (cfg->clock_type) {
89 	case PMC_TYPE_PERIPHERAL:
90 		*rate = SOC_ATMEL_SAM_MCK_FREQ_HZ;
91 		break;
92 	default:
93 		LOG_ERR("The PMC clock type is not implemented.");
94 		return -ENODEV;
95 	}
96 
97 	LOG_DBG("Rate: %d", *rate);
98 
99 	return 0;
100 }
101 
102 static enum clock_control_status
atmel_sam_clock_control_get_status(const struct device * dev,clock_control_subsys_t sys)103 atmel_sam_clock_control_get_status(const struct device *dev,
104 				   clock_control_subsys_t sys)
105 {
106 	ARG_UNUSED(dev);
107 
108 	const struct atmel_sam_pmc_config *cfg = (const struct atmel_sam_pmc_config *)sys;
109 	enum clock_control_status status;
110 
111 	if (cfg == NULL) {
112 		LOG_ERR("The PMC config can not be NULL.");
113 		return -ENXIO;
114 	}
115 
116 	LOG_DBG("Type: %x, Id: %d", cfg->clock_type, cfg->peripheral_id);
117 
118 	switch (cfg->clock_type) {
119 	case PMC_TYPE_PERIPHERAL:
120 		status = soc_pmc_peripheral_is_enabled(cfg->peripheral_id) > 0
121 		       ? CLOCK_CONTROL_STATUS_ON
122 		       : CLOCK_CONTROL_STATUS_OFF;
123 		break;
124 	default:
125 		LOG_ERR("The PMC clock type is not implemented.");
126 		return -ENODEV;
127 	}
128 
129 	return status;
130 }
131 
132 static struct clock_control_driver_api atmel_sam_clock_control_api = {
133 	.on = atmel_sam_clock_control_on,
134 	.off = atmel_sam_clock_control_off,
135 	.get_rate = atmel_sam_clock_control_get_rate,
136 	.get_status = atmel_sam_clock_control_get_status,
137 };
138 
139 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1,
140 		      CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
141 		      &atmel_sam_clock_control_api);
142