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