1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Juno ADC Driver
9  */
10 
11 #include "juno_adc.h"
12 #include "v2m_sys_regs.h"
13 
14 #include <mod_juno_adc.h>
15 #include <mod_sensor.h>
16 
17 #include <fwk_assert.h>
18 #include <fwk_id.h>
19 #include <fwk_module.h>
20 #include <fwk_module_idx.h>
21 #include <fwk_status.h>
22 
23 #include <stddef.h>
24 #include <stdint.h>
25 
26 /*
27  * ADC driver API functions.
28  */
29 
get_value(fwk_id_t id,mod_sensor_value_t * value)30 static int get_value(fwk_id_t id, mod_sensor_value_t *value)
31 {
32 #ifdef BUILD_HAS_SENSOR_SIGNED_VALUE
33     return FWK_E_SUPPORT;
34 #else
35     uint32_t adc_value;
36     uint64_t adc_quantity;
37     enum juno_adc_dev_type dev_type;
38 
39     dev_type = (enum juno_adc_dev_type)fwk_id_get_sub_element_idx(id);
40 
41     switch ((enum juno_adc_sensor_type)fwk_id_get_element_idx(id)) {
42     case ADC_TYPE_CURRENT:
43         adc_value =
44             V2M_SYS_REGS->ADC_CURRENT[dev_type] & JUNO_ADC_SYS_REG_AMPS_MASK;
45 
46         adc_quantity = ((uint64_t)adc_value) * JUNO_ADC_AMPS_MULTIPLIER;
47 
48         if ((dev_type == ADC_DEV_BIG) || (dev_type == ADC_DEV_GPU)) {
49             adc_quantity /= ADC_CURRENT_CONST1;
50         } else {
51             adc_quantity /= ADC_CURRENT_CONST2;
52         }
53 
54         *value = adc_quantity;
55 
56         return FWK_SUCCESS;
57 
58     case ADC_TYPE_VOLT:
59         adc_value =
60             V2M_SYS_REGS->ADC_VOLT[dev_type] & JUNO_ADC_SYS_REG_VOLT_MASK;
61 
62         adc_quantity =
63             (((uint64_t)adc_value) * JUNO_ADC_VOLT_MULTIPLIER) / ADC_VOLT_CONST;
64 
65         *value = adc_quantity;
66 
67         return FWK_SUCCESS;
68 
69     case ADC_TYPE_POWER:
70         adc_value =
71             V2M_SYS_REGS->ADC_POWER[dev_type] & JUNO_ADC_SYS_REG_POWER_MASK;
72 
73         adc_quantity = ((uint64_t)adc_value) * JUNO_ADC_WATTS_MULTIPLIER;
74 
75         if ((dev_type == ADC_DEV_BIG) || (dev_type == ADC_DEV_GPU)) {
76             adc_quantity /= ADC_POWER_CONST1;
77         } else {
78             adc_quantity /= ADC_POWER_CONST2;
79         }
80 
81         *value = adc_quantity;
82 
83         return FWK_SUCCESS;
84 
85     case ADC_TYPE_ENERGY:
86         adc_quantity =
87             V2M_SYS_REGS->ADC_ENERGY[dev_type] * JUNO_ADC_JOULE_MULTIPLIER;
88 
89         if ((dev_type == ADC_DEV_BIG) || (dev_type == ADC_DEV_GPU)) {
90             adc_quantity /= ADC_ENERGY_CONST1;
91         } else {
92             adc_quantity /= ADC_ENERGY_CONST2;
93         }
94 
95         *value = adc_quantity;
96 
97         return FWK_SUCCESS;
98 
99     default:
100         return FWK_E_PARAM;
101     }
102 #endif
103 }
104 
get_info(fwk_id_t id,struct mod_sensor_info * info)105 static int get_info(fwk_id_t id, struct mod_sensor_info *info)
106 {
107     const struct mod_juno_adc_dev_config *config;
108 
109     config = fwk_module_get_data(id);
110 
111     if (!fwk_expect(config->info != NULL)) {
112         return FWK_E_DATA;
113     }
114 
115     *info = *(config->info);
116 
117     return FWK_SUCCESS;
118 }
119 
120 static const struct mod_sensor_driver_api adc_sensor_api = {
121     .get_value = get_value,
122     .get_info = get_info,
123 };
124 
125 /*
126  * Framework handlers.
127  */
juno_adc_init(fwk_id_t module_id,unsigned int element_count,const void * data)128 static int juno_adc_init(fwk_id_t module_id,
129                          unsigned int element_count,
130                          const void *data)
131 {
132     if (!fwk_expect(element_count > 0)) {
133         return FWK_E_DATA;
134     }
135 
136     return FWK_SUCCESS;
137 }
138 
juno_adc_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)139 static int juno_adc_element_init(fwk_id_t element_id,
140                                  unsigned int sub_element_count,
141                                  const void *data)
142 {
143     return FWK_SUCCESS;
144 }
145 
juno_adc_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)146 static int juno_adc_process_bind_request(fwk_id_t source_id,
147                                          fwk_id_t target_id,
148                                          fwk_id_t api_id,
149                                          const void **api)
150 {
151     if (!fwk_module_is_valid_sub_element_id(target_id)) {
152         return FWK_E_ACCESS;
153     }
154 
155     if (fwk_id_get_module_idx(source_id) !=
156         fwk_id_get_module_idx(fwk_module_id_sensor)) {
157         return FWK_E_ACCESS;
158     }
159 
160     if (!fwk_id_is_equal(api_id, mod_juno_adc_api_id_driver)) {
161         return FWK_E_ACCESS;
162     }
163 
164     *api = &adc_sensor_api;
165 
166     return FWK_SUCCESS;
167 }
168 
169 const struct fwk_module module_juno_adc = {
170     .type = FWK_MODULE_TYPE_DRIVER,
171     .api_count = (unsigned int)MOD_JUNO_ADC_API_IDX_COUNT,
172     .init = juno_adc_init,
173     .element_init = juno_adc_element_init,
174     .process_bind_request = juno_adc_process_bind_request
175 };
176