1 /*
2 * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 /** @file
7 * @brief Atmel SAM4L MCU family Power Management (PM) module
8 * HAL driver.
9 */
10
11 #include <soc.h>
12 #include <sys/__assert.h>
13 #include <sys/util.h>
14
15 /**
16 * SAM4L define peripheral-ids out of order. This maps peripheral-id group
17 * to right register index.
18 */
19 static const uint32_t bridge_peripheral_ids[] = {
20 2, /* PBA GRP */
21 3, /* PBB GRP */
22 4, /* PBC GRP */
23 5, /* PBD GRP */
24 1, /* HSB GRP */
25 0, /* CPU GRP */
26 };
27
28 static const uint32_t bridge_peripheral_instances[] = {
29 1, /* CPU MASK Instances */
30 10, /* HSB MASK Instances */
31 24, /* PBA MASK Instances */
32 7, /* PBB MASK Instances */
33 5, /* PBC MASK Instances */
34 6, /* PBD MASK Instances */
35 };
36
soc_pmc_peripheral_enable(uint32_t id)37 void soc_pmc_peripheral_enable(uint32_t id)
38 {
39 uint32_t bus_grp = id >> 5;
40 uint32_t per_idx = id & 0x1F;
41 uint32_t bus_id;
42 uint32_t mask;
43
44 if (bus_grp >= 6) {
45 return;
46 }
47
48 bus_id = bridge_peripheral_ids[bus_grp];
49
50 if (per_idx >= bridge_peripheral_instances[bus_id]) {
51 return;
52 }
53
54 mask = *(&PM->CPUMASK + bus_id);
55 mask |= (1U << per_idx);
56 PM->UNLOCK = PM_UNLOCK_KEY(0xAAu) |
57 PM_UNLOCK_ADDR(((uint32_t)&PM->CPUMASK -
58 (uint32_t)PM) +
59 (4 * bus_id));
60 *(&PM->CPUMASK + bus_id) = mask;
61 }
62
soc_pmc_peripheral_disable(uint32_t id)63 void soc_pmc_peripheral_disable(uint32_t id)
64 {
65 uint32_t bus_grp = id >> 5;
66 uint32_t per_idx = id & 0x1F;
67 uint32_t bus_id;
68 uint32_t mask;
69
70 if (bus_grp >= 6) {
71 return;
72 }
73
74 bus_id = bridge_peripheral_ids[bus_grp];
75
76 if (per_idx >= bridge_peripheral_instances[bus_id]) {
77 return;
78 }
79
80 mask = *(&PM->CPUMASK + bus_id);
81 mask &= ~(1U << per_idx);
82 PM->UNLOCK = PM_UNLOCK_KEY(0xAAu) |
83 PM_UNLOCK_ADDR(((uint32_t)&PM->CPUMASK -
84 (uint32_t)PM) +
85 (4 * bus_id));
86 *(&PM->CPUMASK + bus_id) = mask;
87 }
88
soc_pmc_peripheral_is_enabled(uint32_t id)89 uint32_t soc_pmc_peripheral_is_enabled(uint32_t id)
90 {
91 uint32_t bus_grp = id >> 5;
92 uint32_t per_idx = id & 0x1F;
93 uint32_t bus_id;
94 uint32_t mask;
95
96 if (bus_grp >= 6) {
97 return 0;
98 }
99
100 bus_id = bridge_peripheral_ids[bus_grp];
101
102 if (per_idx >= bridge_peripheral_instances[bus_id]) {
103 return 0;
104 }
105
106 mask = *(&PM->CPUMASK + bus_id);
107
108 return ((mask & (1U << per_idx)) > 0);
109 }
110
soc_pm_enable_pba_divmask(uint32_t mask)111 void soc_pm_enable_pba_divmask(uint32_t mask)
112 {
113 uint32_t temp_mask;
114
115 temp_mask = PM->PBADIVMASK;
116 temp_mask |= mask;
117
118 PM->UNLOCK = PM_UNLOCK_KEY(0xAAu) |
119 PM_UNLOCK_ADDR((uint32_t)&PM->PBADIVMASK -
120 (uint32_t)PM);
121 PM->PBADIVMASK = temp_mask;
122 }
123