1 /**
2   * @file  hal_sdhost.c
3   * @author  ALLWINNERTECH IOT WLAN Team
4   */
5 
6 /*
7  * Copyright (C) 2017 ALLWINNERTECH TECHNOLOGY CO., LTD. All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *    1. Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *    2. Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in the
16  *       documentation and/or other materials provided with the
17  *       distribution.
18  *    3. Neither the name of ALLWINNERTECH TECHNOLOGY CO., LTD. nor the names of
19  *       its contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *  LIMITED TO, )|hhst->sdio_irq_maskPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <hal_gpio.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #ifndef CONFIG_KERNEL_FREERTOS
39 #include <log.h>
40 #endif
41 #include "_sdhost.h"
42 #include "_sd_define.h"
43 
44 #ifndef SDC_MAX_PIN_NUM
45 #define SDC_MAX_PIN_NUM   13
46 #endif
47 
48 typedef struct
49 {
50     uint32_t *pin;
51     uint8_t pin_num : 3;
52     uint8_t pin_mux : 3;
53     uint8_t pin_drv : 2;
54 } sdmmc_pin_t;
55 
56 static sdmmc_pin_t sunxi_sdmmc_pin[4];
57 
58 
sdmmc_pinctl_set_from_cfg(struct mmc_host * host,char * sdc_str,uint32_t pin_num)59 int32_t sdmmc_pinctl_set_from_cfg(struct mmc_host *host, char *sdc_str, uint32_t pin_num)
60 {
61 #ifdef HAL_SetPin
62     int32_t ret = 0;
63     user_gpio_set_t gpiocfg[SDC_MAX_PIN_NUM] = {0};
64     int i = 0;
65     int gpio_num = 0;
66     if (pin_num > SDC_MAX_PIN_NUM) {
67         SDC_LOGE("pin num over %d\n", SDC_MAX_PIN_NUM);
68         return ret;
69     }
70 
71     ret = Hal_Cfg_GetGPIOSecData(sdc_str, gpiocfg, pin_num);
72     if(ret < 0) {
73         SDC_LOGE("%s not has pin setting on sys_config.fex\n", sdc_str);
74         return ret;
75     }
76 
77     for (i = 0;i < pin_num; i++) {
78         SDC_LOGD("name %s,port %d,port_num %d,mul_sel %d, pull %d, drv_level %d\n",\
79                 gpiocfg[i].gpio_name, gpiocfg[i].port, gpiocfg[i].port_num, \
80                 gpiocfg[i].mul_sel, gpiocfg[i].pull, gpiocfg[i].drv_level);
81     }
82 
83     for(i = 0; i< pin_num; i++ ) {
84         gpio_num = (gpiocfg[i].port - 1) * PINS_PER_BANK + gpiocfg[i].port_num;
85         ret = hal_gpio_pinmux_set_function(gpio_num, gpiocfg[i].mul_sel);
86         if (ret) {
87             SDC_LOGE(
88                 "[sdmmc %s] PIN%lu set function failed! return %d\n",
89                 sdc_str, gpio_num, ret);
90             return -1;
91         }
92 
93         ret = hal_gpio_set_driving_level(gpio_num, gpiocfg[i].drv_level);
94         if (ret) {
95             SDC_LOGE(
96                 "[sdmmc %s] PIN%lu set driving level failed! return %d\n",
97                 sdc_str, gpio_num, ret);
98             return -1;
99         }
100         ret = hal_gpio_set_pull(gpio_num, gpiocfg[i].pull);
101         if (ret) {
102             SDC_LOGE(
103                 "[sdmmc %s] PIN%lu set driving level failed! return %d\n",
104                 sdc_str, gpio_num, ret);
105             return -1;
106         }
107     }
108     return ret;
109 #else
110     SDC_LOGN("unsupport sys fex %d\n");
111     return -1;
112 #endif
113 }
114 
115 
sdmmc_pinctrl_init(struct mmc_host * host)116 uint32_t sdmmc_pinctrl_init(struct mmc_host *host)
117 {
118     uint8_t i;
119     uint32_t flags = 0;
120     int ret;
121     uint32_t host_id = host->sdc_id;
122 
123     switch (host_id) {
124         case 0:
125             ret = sdmmc_pinctl_set_from_cfg(host, "sdc0", SDC0_NUM);
126             if(ret < 0) {
127                 sunxi_sdmmc_pin[host_id].pin_num = SDC0_NUM;
128                 sunxi_sdmmc_pin[host_id].pin_mux = SDMMC_MUXSEL;
129                 sunxi_sdmmc_pin[host_id].pin_drv = SDMMC_DRVSEL;
130                 sunxi_sdmmc_pin[host_id].pin = malloc(sizeof(uint32_t) * SDC0_NUM);
131                 sunxi_sdmmc_pin[host_id].pin[0] = SDC0_CLK;
132                 sunxi_sdmmc_pin[host_id].pin[1] = SDC0_CMD;
133                 sunxi_sdmmc_pin[host_id].pin[2] = SDC0_D0;
134                 sunxi_sdmmc_pin[host_id].pin[3] = SDC0_D1;
135                 sunxi_sdmmc_pin[host_id].pin[4] = SDC0_D2;
136                 sunxi_sdmmc_pin[host_id].pin[5] = SDC0_D3;
137                 SDC_LOGE("sdmmc%ld use default pin setting\n", host_id);
138             } else {
139                 SDC_LOGD("sdmmc%ld use pin setting on sys_config.fex\n", host_id);
140                 goto out;
141             }
142             break;
143         case 1:
144             if (host->param.pwr_mode == POWER_MODE_330) {
145                 hal_gpio_sel_vol_mode(SDC1_D0, POWER_MODE_330);
146             } else {
147                 hal_gpio_sel_vol_mode(SDC1_D0, POWER_MODE_180);
148             }
149             ret = sdmmc_pinctl_set_from_cfg(host, "sdc1", SDC1_NUM);
150             if(ret < 0) {
151                             sunxi_sdmmc_pin[host_id].pin_num = SDC1_NUM;
152                             sunxi_sdmmc_pin[host_id].pin_mux = SDMMC_MUXSEL;
153                             sunxi_sdmmc_pin[host_id].pin_drv = SDMMC_DRVSEL;
154                             sunxi_sdmmc_pin[host_id].pin = malloc(sizeof(uint32_t) * SDC1_NUM);
155                             sunxi_sdmmc_pin[host_id].pin[0] = SDC1_CLK;
156                             sunxi_sdmmc_pin[host_id].pin[1] = SDC1_CMD;
157                             sunxi_sdmmc_pin[host_id].pin[2] = SDC1_D0;
158                             // sunxi_sdmmc_pin[host_id].pin[3] = SDC1_D1;
159                             // sunxi_sdmmc_pin[host_id].pin[4] = SDC1_D2;
160                             // sunxi_sdmmc_pin[host_id].pin[5] = SDC1_D3;
161                 SDC_LOGE("sdmmc%ld use default pin setting\n", host_id);
162             } else {
163                 SDC_LOGD("sdmmc%ld use pin setting on sys_config.fex\n", host_id);
164                 goto out;
165             }
166             break;
167         default:
168             SDC_LOGE("sdmmc%ld is invalid\n", host_id);
169             return -1;
170 
171     }
172 
173     for (i = 0; i < sunxi_sdmmc_pin[host_id].pin_num; i++)
174     {
175         ret = hal_gpio_pinmux_set_function(sunxi_sdmmc_pin[host_id].pin[i], sunxi_sdmmc_pin[host_id].pin_mux);
176         if (ret)
177         {
178             SDC_LOGE(
179                 "[sdmmc%ld] PIN%lu set function failed! return %d\n",
180                 host_id, sunxi_sdmmc_pin[host_id].pin[i], ret);
181             return -1;
182         }
183         ret = hal_gpio_set_driving_level(sunxi_sdmmc_pin[host_id].pin[i], sunxi_sdmmc_pin[host_id].pin_drv);
184         if (ret)
185         {
186             SDC_LOGE(
187                 "[sdmmc%ld] PIN%lu set driving level failed! return %d\n",
188                 host_id, sunxi_sdmmc_pin[host_id].pin[i], ret);
189             return -1;
190         }
191         ret = hal_gpio_set_pull(sunxi_sdmmc_pin[host_id].pin[i], GPIO_PULL_UP);
192         // ret = drv_gpio_set_pull_state(sunxi_sdmmc_pin[host_id].pin[i], DRV_GPIO_PULL_DOWN_DISABLE);
193     }
194 out:
195     return 0;
196 }
197 
mmc_gpiod_request_cd_irq(struct mmc_host * host)198 int mmc_gpiod_request_cd_irq(struct mmc_host *host)
199 {
200     uint32_t irq;
201     int ret = 0;
202     gpio_pull_status_t pull_state;
203     gpio_direction_t gpio_direction;
204     gpio_data_t gpio_data;
205 
206     host->cd_gpio_pin = SDC0_DET;
207     /*set gpio detect-clk 24M*/
208     hal_gpio_set_debounce(host->cd_gpio_pin, 1);
209     ret = hal_gpio_to_irq(host->cd_gpio_pin, &irq);
210     if (ret < 0)
211     {
212         SDC_LOGE("gpio to irq error, error num: %d\n", ret);
213         return ret;
214     }
215 
216     /*set pin mux*/
217     ret = hal_gpio_pinmux_set_function(host->cd_gpio_pin, 0);
218     ret = hal_gpio_set_driving_level(host->cd_gpio_pin, 3);
219     ret = hal_gpio_set_pull(host->cd_gpio_pin, 1);
220     if (ret < 0)
221     {
222         SDC_LOGE("set pin mux error!\n");
223         return -1;
224     }
225 
226     host->cd_irq = irq;
227     ret = hal_gpio_irq_request(irq, host->cd_gpio_isr, IRQ_TYPE_EDGE_BOTH, host);
228     if (ret < 0)
229     {
230         SDC_LOGE("request irq error, irq num:%lu error num: %d\n", (unsigned long)irq, ret);
231         return ret;
232     }
233 
234 #if 0
235     ret = drv_gpio_irq_enable(irq);
236     if (ret < 0)
237     {
238         printf("request irq error, error num: %d\n", ret);
239         return ret;
240     }
241     ret = drv_gpio_irq_disable(irq);
242     if (ret < 0)
243     {
244         printf("disable irq error, irq num:%lu,error num: %d\n", irq, ret);
245         return ret;
246     }
247 
248     ret = drv_gpio_irq_free(irq);
249     if (ret < 0)
250     {
251         printf("free irq error, error num: %d\n", ret);
252         return ret;
253     }
254 #endif
255     return ret;
256 }
257 
258