File Index
Files and directories
Sign in
FILE

pinctrl-imx-scmi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pinctrl/freescale/pinctrl-imx-scmi.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * System Control and Power Interface (SCMI) Protocol based i.MX pinctrl driver
  4 *
  5 * Copyright 2024 NXP
  6 */
  7
  8#include <linux/device.h>
  9#include <linux/err.h>
 10#include <linux/errno.h>
 11#include <linux/module.h>
 12#include <linux/mod_devicetable.h>
 13#include <linux/of.h>
 14#include <linux/scmi_protocol.h>
 15#include <linux/seq_file.h>
 16#include <linux/slab.h>
 17#include <linux/types.h>
 18
 19#include <linux/pinctrl/machine.h>
 20#include <linux/pinctrl/pinconf.h>
 21#include <linux/pinctrl/pinconf-generic.h>
 22#include <linux/pinctrl/pinctrl.h>
 23#include <linux/pinctrl/pinmux.h>
 24
 25#include "../pinctrl-utils.h"
 26#include "../core.h"
 27#include "../pinconf.h"
 28#include "../pinmux.h"
 29
 30#define DRV_NAME "scmi-pinctrl-imx"
 31
 32struct scmi_pinctrl_imx {
 33	struct device *dev;
 34	struct scmi_protocol_handle *ph;
 35	struct pinctrl_dev *pctldev;
 36	struct pinctrl_desc pctl_desc;
 37	const struct scmi_pinctrl_proto_ops *ops;
 38};
 39
 40/* SCMI pin control types, aligned with SCMI firmware */
 41#define IMX_SCMI_NUM_CFG	4
 42#define IMX_SCMI_PIN_MUX	192
 43#define IMX_SCMI_PIN_CONFIG	193
 44#define IMX_SCMI_PIN_DAISY_ID	194
 45#define IMX_SCMI_PIN_DAISY_CFG	195
 46
 47#define IMX_SCMI_NO_PAD_CTL		BIT(31)
 48#define IMX_SCMI_PAD_SION		BIT(30)
 49#define IMX_SCMI_IOMUXC_CONFIG_SION	BIT(4)
 50
 51#define IMX_SCMI_PIN_SIZE	24
 52
 53#define IMX95_DAISY_OFF		0x408
 54#define IMX94_DAISY_OFF		0x608
 55
 56static int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 57					   struct device_node *np,
 58					   struct pinctrl_map **map,
 59					   unsigned int *num_maps)
 60{
 61	struct pinctrl_map *new_map;
 62	const __be32 *list;
 63	unsigned long *configs = NULL;
 64	unsigned long cfg[IMX_SCMI_NUM_CFG];
 65	int map_num, size, pin_size, pin_id, num_pins;
 66	int mux_reg, conf_reg, input_reg, mux_val, conf_val, input_val;
 67	int i, j;
 68	uint32_t ncfg;
 69	static uint32_t daisy_off;
 70
 71	if (!daisy_off) {
 72		if (of_machine_is_compatible("fsl,imx95")) {
 73			daisy_off = IMX95_DAISY_OFF;
 74		} else if (of_machine_is_compatible("fsl,imx94")) {
 75			daisy_off = IMX94_DAISY_OFF;
 76		} else {
 77			dev_err(pctldev->dev, "platform not support scmi pinctrl\n");
 78			return -EINVAL;
 79		}
 80	}
 81
 82	list = of_get_property(np, "fsl,pins", &size);
 83	if (!list) {
 84		dev_err(pctldev->dev, "no fsl,pins property in node %pOF\n", np);
 85		return -EINVAL;
 86	}
 87
 88	pin_size = IMX_SCMI_PIN_SIZE;
 89
 90	if (!size || size % pin_size) {
 91		dev_err(pctldev->dev, "Invalid fsl,pins or pins property in node %pOF\n", np);
 92		return -EINVAL;
 93	}
 94
 95	num_pins = size / pin_size;
 96	map_num = num_pins;
 97
 98	new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map),
 99				GFP_KERNEL);
100	if (!new_map)
101		return -ENOMEM;
102
103	*map = new_map;
104	*num_maps = map_num;
105
106	/* create config map */
107	for (i = 0; i < num_pins; i++) {
108		j = 0;
109		ncfg = IMX_SCMI_NUM_CFG;
110		mux_reg = be32_to_cpu(*list++);
111		conf_reg = be32_to_cpu(*list++);
112		input_reg = be32_to_cpu(*list++);
113		mux_val = be32_to_cpu(*list++);
114		input_val = be32_to_cpu(*list++);
115		conf_val = be32_to_cpu(*list++);
116		if (conf_val & IMX_SCMI_PAD_SION)
117			mux_val |= IMX_SCMI_IOMUXC_CONFIG_SION;
118
119		pin_id = mux_reg / 4;
120
121		cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_MUX, mux_val);
122
123		if (!conf_reg || (conf_val & IMX_SCMI_NO_PAD_CTL))
124			ncfg--;
125		else
126			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_CONFIG, conf_val);
127
128		if (!input_reg) {
129			ncfg -= 2;
130		} else {
131			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_DAISY_ID,
132							    (input_reg - daisy_off) / 4);
133			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_DAISY_CFG, input_val);
134		}
135
136		configs = kmemdup_array(cfg, ncfg, sizeof(unsigned long), GFP_KERNEL);
137
138		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
139		new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, pin_id);
140		new_map[i].data.configs.configs = configs;
141		new_map[i].data.configs.num_configs = ncfg;
142	}
143
144	return 0;
145}
146
147static void pinctrl_scmi_imx_dt_free_map(struct pinctrl_dev *pctldev,
148					 struct pinctrl_map *map, unsigned int num_maps)
149{
150	kfree(map);
151}
152
153static const struct pinctrl_ops pinctrl_scmi_imx_pinctrl_ops = {
154	.get_groups_count = pinctrl_generic_get_group_count,
155	.get_group_name = pinctrl_generic_get_group_name,
156	.get_group_pins = pinctrl_generic_get_group_pins,
157	.dt_node_to_map = pinctrl_scmi_imx_dt_node_to_map,
158	.dt_free_map = pinctrl_scmi_imx_dt_free_map,
159};
160
161static int pinctrl_scmi_imx_func_set_mux(struct pinctrl_dev *pctldev,
162					 unsigned int selector, unsigned int group)
163{
164	/*
165	 * For i.MX SCMI PINCTRL , postpone the mux setting
166	 * until config is set as they can be set together
167	 * in one IPC call
168	 */
169	return 0;
170}
171
172static const struct pinmux_ops pinctrl_scmi_imx_pinmux_ops = {
173	.get_functions_count = pinmux_generic_get_function_count,
174	.get_function_name = pinmux_generic_get_function_name,
175	.get_function_groups = pinmux_generic_get_function_groups,
176	.set_mux = pinctrl_scmi_imx_func_set_mux,
177};
178
179static int pinctrl_scmi_imx_pinconf_get(struct pinctrl_dev *pctldev,
180					unsigned int pin, unsigned long *config)
181{
182	int ret;
183	struct scmi_pinctrl_imx *pmx = pinctrl_dev_get_drvdata(pctldev);
184	u32 config_type, val;
185
186	if (!config)
187		return -EINVAL;
188
189	config_type = pinconf_to_config_param(*config);
190
191	ret = pmx->ops->settings_get_one(pmx->ph, pin, PIN_TYPE, config_type, &val);
192	/* Convert SCMI error code to PINCTRL expected error code */
193	if (ret == -EOPNOTSUPP)
194		return -ENOTSUPP;
195	if (ret)
196		return ret;
197
198	*config = pinconf_to_config_packed(config_type, val);
199
200	dev_dbg(pmx->dev, "pin:%s, conf:0x%x", pin_get_name(pctldev, pin), val);
201
202	return 0;
203}
204
205static int pinctrl_scmi_imx_pinconf_set(struct pinctrl_dev *pctldev,
206					unsigned int pin,
207					unsigned long *configs,
208					unsigned int num_configs)
209{
210	struct scmi_pinctrl_imx *pmx = pinctrl_dev_get_drvdata(pctldev);
211	enum scmi_pinctrl_conf_type config_type[IMX_SCMI_NUM_CFG];
212	u32 config_value[IMX_SCMI_NUM_CFG];
213	enum scmi_pinctrl_conf_type *p_config_type = config_type;
214	u32 *p_config_value = config_value;
215	int ret;
216	int i;
217
218	if (!configs || !num_configs)
219		return -EINVAL;
220
221	if (num_configs > IMX_SCMI_NUM_CFG) {
222		dev_err(pmx->dev, "num_configs(%d) too large\n", num_configs);
223		return -EINVAL;
224	}
225
226	for (i = 0; i < num_configs; i++) {
227		/* cast to avoid build warning */
228		p_config_type[i] =
229			(enum scmi_pinctrl_conf_type)pinconf_to_config_param(configs[i]);
230		p_config_value[i] = pinconf_to_config_argument(configs[i]);
231
232		dev_dbg(pmx->dev, "pin: %u, type: %u, val: 0x%x\n",
233			pin, p_config_type[i], p_config_value[i]);
234	}
235
236	ret = pmx->ops->settings_conf(pmx->ph, pin, PIN_TYPE, num_configs,
237				      p_config_type,  p_config_value);
238	if (ret)
239		dev_err(pmx->dev, "Error set config %d\n", ret);
240
241	return ret;
242}
243
244static void pinctrl_scmi_imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
245					      struct seq_file *s, unsigned int pin_id)
246{
247	unsigned long config = pinconf_to_config_packed(IMX_SCMI_PIN_CONFIG, 0);
248	int ret;
249
250	ret = pinctrl_scmi_imx_pinconf_get(pctldev, pin_id, &config);
251	if (ret)
252		config = 0;
253	else
254		config = pinconf_to_config_argument(config);
255
256	seq_printf(s, "0x%lx", config);
257}
258
259static const struct pinconf_ops pinctrl_scmi_imx_pinconf_ops = {
260	.pin_config_get = pinctrl_scmi_imx_pinconf_get,
261	.pin_config_set = pinctrl_scmi_imx_pinconf_set,
262	.pin_config_dbg_show = pinctrl_scmi_imx_pinconf_dbg_show,
263};
264
265static int
266scmi_pinctrl_imx_get_pins(struct scmi_pinctrl_imx *pmx, struct pinctrl_desc *desc)
267{
268	struct pinctrl_pin_desc *pins;
269	unsigned int npins;
270	int ret, i;
271
272	npins = pmx->ops->count_get(pmx->ph, PIN_TYPE);
273	pins = devm_kmalloc_array(pmx->dev, npins, sizeof(*pins), GFP_KERNEL);
274	if (!pins)
275		return -ENOMEM;
276
277	for (i = 0; i < npins; i++) {
278		pins[i].number = i;
279		/* no need free name, firmware driver handles it */
280		ret = pmx->ops->name_get(pmx->ph, i, PIN_TYPE, &pins[i].name);
281		if (ret)
282			return dev_err_probe(pmx->dev, ret,
283					     "Can't get name for pin %d", i);
284	}
285
286	desc->npins = npins;
287	desc->pins = pins;
288	dev_dbg(pmx->dev, "got pins %u", npins);
289
290	return 0;
291}
292
293static const char * const scmi_pinctrl_imx_allowlist[] = {
294	"fsl,imx95",
295	"fsl,imx94",
296	NULL
297};
298
299static int scmi_pinctrl_imx_probe(struct scmi_device *sdev)
300{
301	struct device *dev = &sdev->dev;
302	const struct scmi_handle *handle = sdev->handle;
303	struct scmi_pinctrl_imx *pmx;
304	struct scmi_protocol_handle *ph;
305	const struct scmi_pinctrl_proto_ops *pinctrl_ops;
306	int ret;
307
308	if (!handle)
309		return -EINVAL;
310
311	if (!of_machine_compatible_match(scmi_pinctrl_imx_allowlist))
312		return -ENODEV;
313
314	pinctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PINCTRL, &ph);
315	if (IS_ERR(pinctrl_ops))
316		return PTR_ERR(pinctrl_ops);
317
318	pmx = devm_kzalloc(dev, sizeof(*pmx), GFP_KERNEL);
319	if (!pmx)
320		return -ENOMEM;
321
322	pmx->ph = ph;
323	pmx->ops = pinctrl_ops;
324
325	pmx->dev = dev;
326	pmx->pctl_desc.name = DRV_NAME;
327	pmx->pctl_desc.owner = THIS_MODULE;
328	pmx->pctl_desc.pctlops = &pinctrl_scmi_imx_pinctrl_ops;
329	pmx->pctl_desc.pmxops = &pinctrl_scmi_imx_pinmux_ops;
330	pmx->pctl_desc.confops = &pinctrl_scmi_imx_pinconf_ops;
331
332	ret = scmi_pinctrl_imx_get_pins(pmx, &pmx->pctl_desc);
333	if (ret)
334		return ret;
335
336	pmx->dev = &sdev->dev;
337
338	ret = devm_pinctrl_register_and_init(dev, &pmx->pctl_desc, pmx,
339					     &pmx->pctldev);
340	if (ret)
341		return dev_err_probe(dev, ret, "Failed to register pinctrl\n");
342
343	return pinctrl_enable(pmx->pctldev);
344}
345
346static const struct scmi_device_id scmi_id_table[] = {
347	{ SCMI_PROTOCOL_PINCTRL, "pinctrl-imx" },
348	{ }
349};
350MODULE_DEVICE_TABLE(scmi, scmi_id_table);
351
352static struct scmi_driver scmi_pinctrl_imx_driver = {
353	.name = DRV_NAME,
354	.probe = scmi_pinctrl_imx_probe,
355	.id_table = scmi_id_table,
356};
357module_scmi_driver(scmi_pinctrl_imx_driver);
358
359MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
360MODULE_DESCRIPTION("i.MX SCMI pin controller driver");
361MODULE_LICENSE("GPL");
~/ Read-only file preview.