Commit | Line | Data |
---|---|---|
b96eea71 D |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2016 Freescale Semiconductor, Inc. | |
4 | * Copyright 2017-2018 NXP | |
5 | * Dong Aisheng <aisheng.dong@nxp.com> | |
6 | */ | |
7 | ||
8 | #include <linux/err.h> | |
9 | #include <linux/firmware/imx/sci.h> | |
10 | #include <linux/of_address.h> | |
11 | #include <linux/pinctrl/pinctrl.h> | |
12 | #include <linux/platform_device.h> | |
13 | ||
14 | #include "../core.h" | |
15 | #include "pinctrl-imx.h" | |
16 | ||
17 | enum pad_func_e { | |
18 | IMX_SC_PAD_FUNC_SET = 15, | |
19 | IMX_SC_PAD_FUNC_GET = 16, | |
20 | }; | |
21 | ||
22 | struct imx_sc_msg_req_pad_set { | |
23 | struct imx_sc_rpc_msg hdr; | |
24 | u32 val; | |
25 | u16 pad; | |
4c48e549 | 26 | } __packed __aligned(4); |
b96eea71 D |
27 | |
28 | struct imx_sc_msg_req_pad_get { | |
29 | struct imx_sc_rpc_msg hdr; | |
30 | u16 pad; | |
4c48e549 | 31 | } __packed __aligned(4); |
b96eea71 D |
32 | |
33 | struct imx_sc_msg_resp_pad_get { | |
34 | struct imx_sc_rpc_msg hdr; | |
35 | u32 val; | |
36 | } __packed; | |
37 | ||
d1ff8d07 | 38 | static struct imx_sc_ipc *pinctrl_ipc_handle; |
b96eea71 D |
39 | |
40 | int imx_pinctrl_sc_ipc_init(struct platform_device *pdev) | |
41 | { | |
42 | return imx_scu_get_handle(&pinctrl_ipc_handle); | |
43 | } | |
44 | ||
45 | int imx_pinconf_get_scu(struct pinctrl_dev *pctldev, unsigned pin_id, | |
46 | unsigned long *config) | |
47 | { | |
48 | struct imx_sc_msg_req_pad_get msg; | |
49 | struct imx_sc_msg_resp_pad_get *resp; | |
50 | struct imx_sc_rpc_msg *hdr = &msg.hdr; | |
51 | int ret; | |
52 | ||
53 | hdr->ver = IMX_SC_RPC_VERSION; | |
54 | hdr->svc = IMX_SC_RPC_SVC_PAD; | |
55 | hdr->func = IMX_SC_PAD_FUNC_GET; | |
56 | hdr->size = 2; | |
57 | ||
58 | msg.pad = pin_id; | |
59 | ||
60 | ret = imx_scu_call_rpc(pinctrl_ipc_handle, &msg, true); | |
61 | if (ret) | |
62 | return ret; | |
63 | ||
64 | resp = (struct imx_sc_msg_resp_pad_get *)&msg; | |
65 | *config = resp->val; | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
70 | int imx_pinconf_set_scu(struct pinctrl_dev *pctldev, unsigned pin_id, | |
71 | unsigned long *configs, unsigned num_configs) | |
72 | { | |
73 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
74 | struct imx_sc_msg_req_pad_set msg; | |
75 | struct imx_sc_rpc_msg *hdr = &msg.hdr; | |
76 | unsigned int mux = configs[0]; | |
77 | unsigned int conf = configs[1]; | |
78 | unsigned int val; | |
79 | int ret; | |
80 | ||
81 | /* | |
82 | * Set mux and conf together in one IPC call | |
83 | */ | |
84 | WARN_ON(num_configs != 2); | |
85 | ||
86 | val = conf | BM_PAD_CTL_IFMUX_ENABLE | BM_PAD_CTL_GP_ENABLE; | |
87 | val |= mux << BP_PAD_CTL_IFMUX; | |
88 | ||
89 | hdr->ver = IMX_SC_RPC_VERSION; | |
90 | hdr->svc = IMX_SC_RPC_SVC_PAD; | |
91 | hdr->func = IMX_SC_PAD_FUNC_SET; | |
92 | hdr->size = 3; | |
93 | ||
94 | msg.pad = pin_id; | |
95 | msg.val = val; | |
96 | ||
97 | ret = imx_scu_call_rpc(pinctrl_ipc_handle, &msg, true); | |
98 | ||
99 | dev_dbg(ipctl->dev, "write: pin_id %u config 0x%x val 0x%x\n", | |
100 | pin_id, conf, val); | |
101 | ||
102 | return ret; | |
103 | } | |
104 | ||
105 | void imx_pinctrl_parse_pin_scu(struct imx_pinctrl *ipctl, | |
106 | unsigned int *pin_id, struct imx_pin *pin, | |
107 | const __be32 **list_p) | |
108 | { | |
109 | const struct imx_pinctrl_soc_info *info = ipctl->info; | |
110 | struct imx_pin_scu *pin_scu = &pin->conf.scu; | |
111 | const __be32 *list = *list_p; | |
112 | ||
113 | pin->pin = be32_to_cpu(*list++); | |
114 | *pin_id = pin->pin; | |
115 | pin_scu->mux_mode = be32_to_cpu(*list++); | |
116 | pin_scu->config = be32_to_cpu(*list++); | |
117 | *list_p = list; | |
118 | ||
119 | dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin->pin].name, | |
120 | pin_scu->mux_mode, pin_scu->config); | |
121 | } |