• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "stm32mp1_adc.h"
17 #include "device_resource_if.h"
18 #include "hdf_device_desc.h"
19 #include "hdf_log.h"
20 #include "osal_io.h"
21 #include "osal_mem.h"
22 #include "osal_time.h"
23 #include "stm32mp1xx.h"
24 #include "stm32mp1xx_hal_conf.h"
25 
26 #define HDF_LOG_TAG stm32mp1_adc
27 
Mp1xxAdcPinInit(struct Mp1xxAdcDevice * stm32mp1)28 static void Mp1xxAdcPinInit(struct Mp1xxAdcDevice *stm32mp1)
29 {
30     uint32_t i;
31     uint32_t value;
32     volatile unsigned char  *gpioBase;
33     volatile unsigned char  *comBase;
34 
35     gpioBase = OsalIoRemap(MP1XX_GPIO_BASE + MP1XX_GPIO_MODE_REG_OFFSET,
36         MP1XX_GPIO_GROUP_NUMBER * MP1XX_GPIO_GROUP_SIZE);
37     for (i = 0; i < MP1XX_ADC_CHANNEL_COUNT_MAX; i++) {
38         if (stm32mp1->validChannel[i] == 0 || stm32mp1->pins[i * MP1_ADC_PIN_DATA_WIDTH] >= MP1XX_GPIO_GROUP_NUMBER) {
39             continue;
40         }
41 
42         value = OSAL_READL(gpioBase);
43         value |= (MP1XX_GPIO_ANALOG_MODE_MASK << MP1XX_GPIO_REG_PIN_SHIFT);
44         OSAL_WRITEL(value, MP1XX_GPIO_BASE + MP1XX_GPIO_MODE_REG_OFFSET);
45 
46         RCC->MC_AHB4ENSETR |= 0x1U << stm32mp1->pins[i * MP1_ADC_PIN_DATA_WIDTH];
47     }
48     RCC->PLL4CR |= 0x1U;
49     comBase = OsalIoRemap(MP1XX_ADC_COMMON_REG_BASE, MP1XX_ADC_COMMON_REG_SIZE);
50     OSAL_WRITEL(MP1XX_ADC_CKMODE_SEL, comBase + MP1XX_ADC_CCR_OFFSET);
51     if (stm32mp1->devNum == MP1XX_ADC_DEVICE_2) {
52         value = stm32mp1->validChannel[MP1XX_ADC_VDDCORE_CHANNEL] & 0x1U;     // VddCore
53         OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_OR_OFFSET);
54         value = stm32mp1->validChannel[MP1XX_ADC_VREF_CHANNEL] & 0x1U;        // Vref
55         value |= (stm32mp1->validChannel[MP1XX_ADC_TSEN_CHANNEL] & 0x1U) << MP1XX_ADC_VREF_SHIFT; // Tsen
56         value |= (stm32mp1->validChannel[MP1XX_ADC_VBAT_CHANNEL] & 0x1U) << MP1XX_ADC_VBAT_SHIFT; // Vbat
57         OSAL_WRITEL(value, comBase + MP1XX_ADC_CCR_OFFSET);
58     }
59 }
60 
Mp1xxAdcReset(struct Mp1xxAdcDevice * stm32mp1)61 static inline void Mp1xxAdcReset(struct Mp1xxAdcDevice *stm32mp1)
62 {
63     (void)stm32mp1;
64 }
65 
Mp1xxAdcSetConfig(struct Mp1xxAdcDevice * stm32mp1)66 static inline void Mp1xxAdcSetConfig(struct Mp1xxAdcDevice *stm32mp1)
67 {
68     uint32_t value;
69 
70     value = 0x1U << MP1XX_ADC_JQDIS_SHIFT;
71     OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_CFGR_OFFSET);
72 }
73 
Mp1xxAdcSetSampleTime(struct Mp1xxAdcDevice * stm32mp1)74 static inline void Mp1xxAdcSetSampleTime(struct Mp1xxAdcDevice *stm32mp1)
75 {
76     uint32_t sampleTime;
77     uint32_t i;
78 
79     sampleTime = 0;
80     for (i = 0; i < MP1XX_CHANNLE_NUM_PER_REG; i++) {
81         sampleTime |= (stm32mp1->sampleTime & MP1XX_SAMPLE_TIME_MASK) << (i * MP1XX_SAMPLE_TIME_BITS);
82     }
83     OSAL_WRITEL(sampleTime, stm32mp1->regBase + MP1XX_ADC_SMPR1_OFFSET);
84     OSAL_WRITEL(sampleTime, stm32mp1->regBase + MP1XX_ADC_SMPR2_OFFSET);
85 }
86 
Mp1xxAdcCalibration(struct Mp1xxAdcDevice * stm32mp1)87 static void Mp1xxAdcCalibration(struct Mp1xxAdcDevice *stm32mp1)
88 {
89     uint32_t value;
90     uint32_t delay = 0;
91 
92     OSAL_WRITEL(0, stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
93     OSAL_WRITEL(MP1XX_ADC_REGULATOR_EN, stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
94     while (1) {
95         value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_ISR_OFFSET);
96         if (((value >> MP1XX_ADC_REGULATOR_RDY_SHIFT) & 0x1U) == 1 || delay > MP1XX_ADC_CAL_TIME_OUT) {
97             break;
98         }
99         OsalMDelay(1);
100         delay++;
101     }
102     delay = 0;
103     value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
104     value |= 0x1U << MP1XX_ADC_ADCAL_SHIFT;
105     OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
106     while (1) {
107         value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
108         if (((value >> MP1XX_ADC_ADCAL_SHIFT) & 0x1U) == 0 || delay > MP1XX_ADC_CAL_TIME_OUT) {
109             break;
110         }
111         OsalMDelay(1);
112         delay++;
113     }
114 }
115 
Mp1xxAdcClkEnable(struct Mp1xxAdcDevice * stm32mp1)116 static inline void Mp1xxAdcClkEnable(struct Mp1xxAdcDevice *stm32mp1)
117 {
118     (void)stm32mp1;
119     static bool hasInit = false;
120     if (hasInit == true) {
121         return;
122     }
123 
124     __HAL_RCC_ADC12_CLK_ENABLE();
125     hasInit = true;
126 }
127 
Mp1xxAdcEnable(struct Mp1xxAdcDevice * stm32mp1)128 static inline void Mp1xxAdcEnable(struct Mp1xxAdcDevice *stm32mp1)
129 {
130     uint32_t value = 0;
131 
132     value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
133     OSAL_WRITEL((value | 1), stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
134 }
135 
Mp1xxAdcDeviceInit(struct Mp1xxAdcDevice * stm32mp1)136 static inline void Mp1xxAdcDeviceInit(struct Mp1xxAdcDevice *stm32mp1)
137 {
138     if (!stm32mp1->adcEnable) {
139         return;
140     }
141     Mp1xxAdcClkEnable(stm32mp1);
142     Mp1xxAdcPinInit(stm32mp1);
143     Mp1xxAdcCalibration(stm32mp1);
144     Mp1xxAdcReset(stm32mp1);
145     Mp1xxAdcSetConfig(stm32mp1);
146     Mp1xxAdcSetSampleTime(stm32mp1);
147     Mp1xxAdcEnable(stm32mp1);
148 }
149 
Mp1xxAdcStart(struct Mp1xxAdcDevice * stm32mp1)150 static inline void Mp1xxAdcStart(struct Mp1xxAdcDevice *stm32mp1)
151 {
152     uint32_t value;
153 
154     value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
155 
156     value |= 0x1U << MP1XX_ADC_ADSTART_SHIFT;
157     value |= MP1XX_ADC_ENABLE;
158     OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_CR_OFFSET);
159 }
160 
Mp1xxAdcOpen(struct AdcDevice * device)161 static int32_t Mp1xxAdcOpen(struct AdcDevice *device)
162 {
163     struct Mp1xxAdcDevice *stm32mp1 = NULL;
164 
165     if (device == NULL) {
166         HDF_LOGE("%s: device is NULL!", __func__);
167         return HDF_ERR_INVALID_OBJECT;
168     }
169 
170     stm32mp1 = (struct Mp1xxAdcDevice *)device;
171     if (!stm32mp1->adcEnable) {
172         HDF_LOGE("%s: ADC %u is disabled!", __func__, stm32mp1->devNum);
173         return HDF_ERR_NOT_SUPPORT;
174     }
175 
176     Mp1xxAdcStart(stm32mp1);
177     return HDF_SUCCESS;
178 }
179 
Mp1xxAdcClose(struct AdcDevice * device)180 static int32_t Mp1xxAdcClose(struct AdcDevice *device)
181 {
182     (void)device;
183     return HDF_SUCCESS;
184 }
185 
Mp1xxAdcSetSequence(struct Mp1xxAdcDevice * stm32mp1,uint32_t channel)186 static inline void Mp1xxAdcSetSequence(struct Mp1xxAdcDevice *stm32mp1, uint32_t channel)
187 {
188     uint32_t value;
189 
190     if (channel >= MP1XX_ADC_CHANNEL_COUNT_MAX) {
191         return;
192     }
193     value = channel << MP1XX_ADC_SQ1_SHIFT;
194     OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_SQR1_OFFSET);
195 
196     value = 0x1U << channel;
197     OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_PCSEL_OFFSET);
198 }
199 
Mp1xxAdcRead(struct AdcDevice * device,uint32_t channel,uint32_t * val)200 static int32_t Mp1xxAdcRead(struct AdcDevice *device, uint32_t channel, uint32_t *val)
201 {
202     uint32_t value;
203     uint32_t delay = 0;
204     struct Mp1xxAdcDevice *stm32mp1 = NULL;
205 
206     if (device == NULL || val == NULL) {
207         HDF_LOGE("%s: device or val is NULL!", __func__);
208         return HDF_ERR_INVALID_OBJECT;
209     }
210 
211     if (channel >= MP1XX_ADC_CHANNEL_COUNT_MAX) {
212         HDF_LOGE("%s: invalid channel: %u!", __func__, channel);
213         return HDF_ERR_INVALID_PARAM;
214     }
215 
216     stm32mp1 = (struct Mp1xxAdcDevice *)device;
217     if (!stm32mp1->adcEnable) {
218         HDF_LOGE("%s: ADC %u is disabled!", __func__, stm32mp1->devNum);
219         return HDF_ERR_NOT_SUPPORT;
220     }
221 
222     Mp1xxAdcSetSequence(stm32mp1, channel);
223     Mp1xxAdcStart(stm32mp1);
224     while (true) {
225         value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_ISR_OFFSET);
226         if ((value & MP1XX_ADC_EOC_MASK) != 0 || delay > MP1XX_ADC_CONV_TIME_OUT) {
227             OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_ADC_ISR_OFFSET);
228             break;
229         }
230         OsalUDelay(1);
231         delay++;
232     }
233 
234     value = OSAL_READL(stm32mp1->regBase + MP1XX_ADC_DR_OFFSET);
235     *val = value >> (MP1XX_ADC_DATA_WIDTH_MAX - stm32mp1->dataWidth);
236 
237     return HDF_SUCCESS;
238 }
239 
240 static const struct AdcMethod g_method = {
241     .start = Mp1xxAdcOpen,
242     .stop = Mp1xxAdcClose,
243     .read = Mp1xxAdcRead,
244 };
245 
Mp1xxAdcReadDrs(struct Mp1xxAdcDevice * stm32mp1,const struct DeviceResourceNode * node)246 static int32_t Mp1xxAdcReadDrs(struct Mp1xxAdcDevice *stm32mp1, const struct DeviceResourceNode *node)
247 {
248     int32_t ret;
249     struct DeviceResourceIface *drsOps = NULL;
250 
251     drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
252     if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint8Array == NULL || drsOps->GetBool == NULL) {
253         HDF_LOGE("%s: invalid drs ops", __func__);
254         return HDF_ERR_NOT_SUPPORT;
255     }
256 
257     ret = drsOps->GetUint32(node, "reg_pbase", &stm32mp1->regBasePhy, 0);
258     if (ret != HDF_SUCCESS) {
259         HDF_LOGE("%s: read regBasePhy failed", __func__);
260         return ret;
261     }
262 
263     ret = drsOps->GetUint32(node, "reg_size", &stm32mp1->regSize, 0);
264     if (ret != HDF_SUCCESS) {
265         HDF_LOGE("%s: read regSize failed", __func__);
266         return ret;
267     }
268 
269     ret = drsOps->GetUint32(node, "dev_num", &stm32mp1->devNum, 0);
270     if (ret != HDF_SUCCESS) {
271         HDF_LOGE("%s: read devNum failed", __func__);
272         return ret;
273     }
274 
275     ret = drsOps->GetUint8Array(node, "channel_enable", stm32mp1->validChannel, MP1XX_ADC_CHANNEL_COUNT_MAX, 0);
276     if (ret != HDF_SUCCESS) {
277         HDF_LOGE("%s: read validChannel failed", __func__);
278         return ret;
279     }
280 
281     ret = drsOps->GetUint32(node, "sample_time", &stm32mp1->sampleTime, 0);
282     if (ret != HDF_SUCCESS) {
283         HDF_LOGE("%s: read sampleTime failed", __func__);
284         return ret;
285     }
286 
287     ret = drsOps->GetUint32(node, "data_width", &stm32mp1->dataWidth, 0);
288     if (ret != HDF_SUCCESS) {
289         HDF_LOGE("%s: read dataWidth failed", __func__);
290         return ret;
291     }
292 
293     stm32mp1->adcEnable = drsOps->GetBool(node, "adc_enable");
294 
295     ret = drsOps->GetUint8Array(node, "pins", stm32mp1->pins, MP1XX_ADC_CHANNEL_COUNT_MAX, 0);
296     if (ret != HDF_SUCCESS) {
297         HDF_LOGE("%s: read pin failed", __func__);
298         return ret;
299     }
300 
301     return HDF_SUCCESS;
302 }
303 
Mp1xxAdcParseInit(struct HdfDeviceObject * device,struct DeviceResourceNode * node)304 static int32_t Mp1xxAdcParseInit(struct HdfDeviceObject *device, struct DeviceResourceNode *node)
305 {
306     int32_t ret;
307     struct Mp1xxAdcDevice *stm32mp1 = NULL;
308     (void)device;
309 
310     stm32mp1 = (struct Mp1xxAdcDevice *)OsalMemCalloc(sizeof(*stm32mp1));
311     if (stm32mp1 == NULL) {
312         HDF_LOGE("%s: alloc stm32mp1 failed", __func__);
313         return HDF_ERR_MALLOC_FAIL;
314     }
315 
316     ret = Mp1xxAdcReadDrs(stm32mp1, node);
317     if (ret != HDF_SUCCESS) {
318         HDF_LOGE("%s: read drs failed:%d", __func__, ret);
319         goto ERR;
320     }
321 
322     stm32mp1->regBase = OsalIoRemap(stm32mp1->regBasePhy, stm32mp1->regSize);
323     if (stm32mp1->regBase == NULL) {
324         HDF_LOGE("%s: remap regbase failed", __func__);
325         ret = HDF_ERR_IO;
326         goto ERR;
327     }
328 
329     Mp1xxAdcDeviceInit(stm32mp1);
330     stm32mp1->device.priv = (void *)node;
331     stm32mp1->device.devNum = stm32mp1->devNum;
332     stm32mp1->device.ops = &g_method;
333     ret = AdcDeviceAdd(&stm32mp1->device);
334     if (ret != HDF_SUCCESS) {
335         HDF_LOGE("%s: add adc device:%u failed", __func__, stm32mp1->devNum);
336         goto ERR;
337     }
338     return HDF_SUCCESS;
339 
340 ERR:
341     if (stm32mp1 != NULL) {
342         if (stm32mp1->regBase != NULL) {
343             OsalIoUnmap((void *)stm32mp1->regBase);
344             stm32mp1->regBase = NULL;
345         }
346         AdcDeviceRemove(&stm32mp1->device);
347         OsalMemFree(stm32mp1);
348     }
349     return ret;
350 }
351 
Mp1xxAdcInit(struct HdfDeviceObject * device)352 static int32_t Mp1xxAdcInit(struct HdfDeviceObject *device)
353 {
354     int32_t ret;
355     struct DeviceResourceNode *childNode = NULL;
356 
357     HDF_LOGI("%s: Enter", __func__);
358     if (device == NULL || device->property == NULL) {
359         HDF_LOGE("%s: device or property is null", __func__);
360         return HDF_ERR_INVALID_OBJECT;
361     }
362 
363     ret = HDF_SUCCESS;
364     DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode)
365     {
366         ret = Mp1xxAdcParseInit(device, childNode);
367         if (ret != HDF_SUCCESS) {
368             break;
369         }
370     }
371     return ret;
372 }
373 
Mp1xxAdcRemoveByNode(const struct DeviceResourceNode * node)374 static void Mp1xxAdcRemoveByNode(const struct DeviceResourceNode *node)
375 {
376     int32_t ret;
377     int32_t devNum;
378     struct AdcDevice *device = NULL;
379     struct Mp1xxAdcDevice *stm32mp1 = NULL;
380     struct DeviceResourceIface *drsOps = NULL;
381 
382     drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
383     if (drsOps == NULL || drsOps->GetUint32 == NULL) {
384         HDF_LOGE("%s: invalid drs ops", __func__);
385         return;
386     }
387 
388     ret = drsOps->GetUint32(node, "devNum", (uint32_t *)&devNum, 0);
389     if (ret != HDF_SUCCESS) {
390         HDF_LOGE("%s: read devNum failed", __func__);
391         return;
392     }
393 
394     device = AdcDeviceGet(devNum);
395     if (device != NULL && device->priv == node) {
396         AdcDevicePut(device);
397         AdcDeviceRemove(device);
398         stm32mp1 = (struct Mp1xxAdcDevice *)device;
399         OsalIoUnmap((void *)stm32mp1->regBase);
400         OsalMemFree(stm32mp1);
401     }
402     return;
403 }
404 
Mp1xxAdcRelease(struct HdfDeviceObject * device)405 static void Mp1xxAdcRelease(struct HdfDeviceObject *device)
406 {
407     const struct DeviceResourceNode *childNode = NULL;
408 
409     HDF_LOGI("%s: enter", __func__);
410     if (device == NULL || device->property == NULL) {
411         HDF_LOGE("%s: device or property is null", __func__);
412         return;
413     }
414     DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode)
415     {
416         Mp1xxAdcRemoveByNode(childNode);
417     }
418 }
419 
420 static struct HdfDriverEntry g_stm32mp1AdcDriverEntry = {
421     .moduleVersion = 1,
422     .Init = Mp1xxAdcInit,
423     .Release = Mp1xxAdcRelease,
424     .moduleName = "stm32mp157_adc_driver",
425 };
426 HDF_INIT(g_stm32mp1AdcDriverEntry);
427