228 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * Copyright (c) 2006-2022, RT-Thread Development Team
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * Change Logs:
 | |
|  * Date           Author       Notes
 | |
|  * 2022-11-26     GuEe-GUI     first version
 | |
|  */
 | |
| 
 | |
| #include <rtthread.h>
 | |
| #include <rtservice.h>
 | |
| #include <rtdevice.h>
 | |
| 
 | |
| #define DBG_TAG "rtdm.pinctrl"
 | |
| #define DBG_LVL DBG_INFO
 | |
| #include <rtdbg.h>
 | |
| 
 | |
| #ifdef RT_USING_OFW
 | |
| static rt_err_t ofw_pin_ctrl_confs_apply(struct rt_ofw_node *np, int index)
 | |
| {
 | |
|     rt_err_t err = -RT_EEMPTY;
 | |
|     rt_phandle phandle;
 | |
|     const fdt32_t *cell;
 | |
|     struct rt_ofw_prop *prop;
 | |
|     char pinctrl_n_name[sizeof("pinctrl-0")];
 | |
| 
 | |
|     rt_sprintf(pinctrl_n_name, "pinctrl-%d", index);
 | |
|     index = 0;
 | |
| 
 | |
|     rt_ofw_foreach_prop_u32(np, pinctrl_n_name, prop, cell, phandle)
 | |
|     {
 | |
|         struct rt_device_pin *pinctrl = RT_NULL;
 | |
|         struct rt_ofw_node *conf_np, *pinctrl_np;
 | |
| 
 | |
|         conf_np = pinctrl_np = rt_ofw_find_node_by_phandle(phandle);
 | |
| 
 | |
|         if (!conf_np)
 | |
|         {
 | |
|             err = -RT_EIO;
 | |
| 
 | |
|             break;
 | |
|         }
 | |
|         /*
 | |
|          * We always assume the phandle in pinctrl-N is the pinctrl-device
 | |
|          * node's child node. If not, we need a better way to find it:
 | |
|          *
 | |
|          *  / {
 | |
|          *      serial@4600 {
 | |
|          *          device_type = "serial";
 | |
|          *          reg = <0x4600 0x100>;
 | |
|          *          clock-frequency = <0>;
 | |
|          *          pinctrl-names = "default";
 | |
|          *          pinctrl-0 = <&uart_pin>;
 | |
|          *      };
 | |
|          *
 | |
|          *      i2c@4700 {
 | |
|          *          reg = <0x4700 0x100>;
 | |
|          *          pinctrl-names = "default";
 | |
|          *          pinctrl-0 = <&i2c_pin_scl, &i2c_pin_sda>;
 | |
|          *      };
 | |
|          *
 | |
|          *      pinctrl: pinctrl {
 | |
|          *
 | |
|          *          uart_pin {
 | |
|          *              multi,pins =
 | |
|          *                  <0 PD0 1 &uart_rx_pull_up>,
 | |
|          *                  <0 PD1 1 &uart_tx_pull_up>;
 | |
|          *          };
 | |
|          *
 | |
|          *          i2c_pin_scl {
 | |
|          *              single,pins = <0 PB1>;
 | |
|          *              pull = <&i2c_pull_none_smt>;
 | |
|          *              function = <1>;
 | |
|          *          };
 | |
|          *
 | |
|          *          i2c_pin_sda {
 | |
|          *              single,pins = <0 PB2>;
 | |
|          *              pull = <&i2c_pull_none_smt>;
 | |
|          *              function = <1>;
 | |
|          *          };
 | |
|          *      };
 | |
|          *  }
 | |
|          */
 | |
|         rt_ofw_foreach_parent_node(pinctrl_np)
 | |
|         {
 | |
|             if (rt_ofw_prop_read_bool(pinctrl_np, "compatible"))
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (pinctrl_np)
 | |
|         {
 | |
|             pinctrl = rt_ofw_data(pinctrl_np);
 | |
| 
 | |
|             rt_ofw_node_put(pinctrl_np);
 | |
|         }
 | |
| 
 | |
|         if (!pinctrl || !pinctrl->ops || !pinctrl->ops->pin_ctrl_confs_apply)
 | |
|         {
 | |
|             if (index)
 | |
|             {
 | |
|                 err = -RT_EEMPTY;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 err = -RT_ERROR;
 | |
|             }
 | |
| 
 | |
|             rt_ofw_node_put(conf_np);
 | |
| 
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         err = pinctrl->ops->pin_ctrl_confs_apply(&pinctrl->parent, conf_np);
 | |
|         rt_ofw_node_put(conf_np);
 | |
| 
 | |
|         if (err)
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         ++index;
 | |
|     }
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| static int ofw_pin_ctrl_confs_lookup(struct rt_ofw_node *np, const char *name)
 | |
| {
 | |
|     return rt_ofw_prop_index_of_string(np, "pinctrl-names", name);
 | |
| }
 | |
| 
 | |
| static rt_err_t ofw_pin_ctrl_confs_apply_by_name(struct rt_ofw_node *np, const char *name)
 | |
| {
 | |
|     int index;
 | |
|     rt_err_t err;
 | |
| 
 | |
|     index = ofw_pin_ctrl_confs_lookup(np, name);
 | |
| 
 | |
|     if (index >= 0)
 | |
|     {
 | |
|         err = ofw_pin_ctrl_confs_apply(np, index);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         err = -RT_EEMPTY;
 | |
|     }
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| #endif /* RT_USING_OFW */
 | |
| 
 | |
| rt_ssize_t rt_pin_ctrl_confs_lookup(struct rt_device *device, const char *name)
 | |
| {
 | |
|     rt_ssize_t res;
 | |
| 
 | |
|     if (device && name)
 | |
|     {
 | |
|         res = -RT_ENOSYS;
 | |
| 
 | |
|     #ifdef RT_USING_OFW
 | |
|         if (device->ofw_node)
 | |
|         {
 | |
|             res = ofw_pin_ctrl_confs_lookup(device->ofw_node, name);
 | |
|         }
 | |
|     #endif /* RT_USING_OFW */
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         res = -RT_EINVAL;
 | |
|     }
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index)
 | |
| {
 | |
|     rt_err_t err;
 | |
| 
 | |
|     if (device && index >= 0)
 | |
|     {
 | |
|         err = -RT_ENOSYS;
 | |
| 
 | |
|     #ifdef RT_USING_OFW
 | |
|         if (device->ofw_node)
 | |
|         {
 | |
|             err = ofw_pin_ctrl_confs_apply(device->ofw_node, index);
 | |
|         }
 | |
|     #endif /* RT_USING_OFW */
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         err = -RT_EINVAL;
 | |
|     }
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name)
 | |
| {
 | |
|     rt_err_t err;
 | |
| 
 | |
|     if (device)
 | |
|     {
 | |
|         if (!name)
 | |
|         {
 | |
|             name = "default";
 | |
|         }
 | |
| 
 | |
|         err = -RT_ENOSYS;
 | |
| 
 | |
|     #ifdef RT_USING_OFW
 | |
|         if (device->ofw_node)
 | |
|         {
 | |
|             err = ofw_pin_ctrl_confs_apply_by_name(device->ofw_node, name);
 | |
|         }
 | |
|     #endif /* RT_USING_OFW */
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         err = -RT_EINVAL;
 | |
|     }
 | |
| 
 | |
|     return err;
 | |
| }
 |