228 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			228 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * 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; | ||
|  | } |