xref: /openbmc/linux/drivers/gpio/gpio-imx-scu.c (revision 0bd459dd)
1*0bd459ddSShenwei Wang // SPDX-License-Identifier: GPL-2.0-only
2*0bd459ddSShenwei Wang /*
3*0bd459ddSShenwei Wang  * Copyright 2021~2022 NXP
4*0bd459ddSShenwei Wang  *
5*0bd459ddSShenwei Wang  * The driver exports a standard gpiochip interface
6*0bd459ddSShenwei Wang  * to control the PIN resources on SCU domain.
7*0bd459ddSShenwei Wang  */
8*0bd459ddSShenwei Wang 
9*0bd459ddSShenwei Wang #include <linux/module.h>
10*0bd459ddSShenwei Wang #include <linux/gpio/driver.h>
11*0bd459ddSShenwei Wang #include <linux/platform_device.h>
12*0bd459ddSShenwei Wang #include <linux/firmware/imx/svc/rm.h>
13*0bd459ddSShenwei Wang #include <dt-bindings/firmware/imx/rsrc.h>
14*0bd459ddSShenwei Wang 
15*0bd459ddSShenwei Wang struct scu_gpio_priv {
16*0bd459ddSShenwei Wang 	struct gpio_chip	chip;
17*0bd459ddSShenwei Wang 	struct mutex		lock;
18*0bd459ddSShenwei Wang 	struct device		*dev;
19*0bd459ddSShenwei Wang 	struct imx_sc_ipc	*handle;
20*0bd459ddSShenwei Wang };
21*0bd459ddSShenwei Wang 
22*0bd459ddSShenwei Wang static unsigned int scu_rsrc_arr[] = {
23*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R0,
24*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R1,
25*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R2,
26*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R3,
27*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R4,
28*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R5,
29*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R6,
30*0bd459ddSShenwei Wang 	IMX_SC_R_BOARD_R7,
31*0bd459ddSShenwei Wang };
32*0bd459ddSShenwei Wang 
33*0bd459ddSShenwei Wang static int imx_scu_gpio_get(struct gpio_chip *chip, unsigned int offset)
34*0bd459ddSShenwei Wang {
35*0bd459ddSShenwei Wang 	struct scu_gpio_priv *priv = gpiochip_get_data(chip);
36*0bd459ddSShenwei Wang 	int level;
37*0bd459ddSShenwei Wang 	int err;
38*0bd459ddSShenwei Wang 
39*0bd459ddSShenwei Wang 	if (offset >= chip->ngpio)
40*0bd459ddSShenwei Wang 		return -EINVAL;
41*0bd459ddSShenwei Wang 
42*0bd459ddSShenwei Wang 	mutex_lock(&priv->lock);
43*0bd459ddSShenwei Wang 
44*0bd459ddSShenwei Wang 	/* to read PIN state via scu api */
45*0bd459ddSShenwei Wang 	err = imx_sc_misc_get_control(priv->handle,
46*0bd459ddSShenwei Wang 			scu_rsrc_arr[offset], 0, &level);
47*0bd459ddSShenwei Wang 	mutex_unlock(&priv->lock);
48*0bd459ddSShenwei Wang 
49*0bd459ddSShenwei Wang 	if (err) {
50*0bd459ddSShenwei Wang 		dev_err(priv->dev, "SCU get failed: %d\n", err);
51*0bd459ddSShenwei Wang 		return err;
52*0bd459ddSShenwei Wang 	}
53*0bd459ddSShenwei Wang 
54*0bd459ddSShenwei Wang 	return level;
55*0bd459ddSShenwei Wang }
56*0bd459ddSShenwei Wang 
57*0bd459ddSShenwei Wang static void imx_scu_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
58*0bd459ddSShenwei Wang {
59*0bd459ddSShenwei Wang 	struct scu_gpio_priv *priv = gpiochip_get_data(chip);
60*0bd459ddSShenwei Wang 	int err;
61*0bd459ddSShenwei Wang 
62*0bd459ddSShenwei Wang 	if (offset >= chip->ngpio)
63*0bd459ddSShenwei Wang 		return;
64*0bd459ddSShenwei Wang 
65*0bd459ddSShenwei Wang 	mutex_lock(&priv->lock);
66*0bd459ddSShenwei Wang 
67*0bd459ddSShenwei Wang 	/* to set PIN output level via scu api */
68*0bd459ddSShenwei Wang 	err = imx_sc_misc_set_control(priv->handle,
69*0bd459ddSShenwei Wang 			scu_rsrc_arr[offset], 0, value);
70*0bd459ddSShenwei Wang 	mutex_unlock(&priv->lock);
71*0bd459ddSShenwei Wang 
72*0bd459ddSShenwei Wang 	if (err)
73*0bd459ddSShenwei Wang 		dev_err(priv->dev, "SCU set (%d) failed: %d\n",
74*0bd459ddSShenwei Wang 				scu_rsrc_arr[offset], err);
75*0bd459ddSShenwei Wang }
76*0bd459ddSShenwei Wang 
77*0bd459ddSShenwei Wang static int imx_scu_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
78*0bd459ddSShenwei Wang {
79*0bd459ddSShenwei Wang 	if (offset >= chip->ngpio)
80*0bd459ddSShenwei Wang 		return -EINVAL;
81*0bd459ddSShenwei Wang 
82*0bd459ddSShenwei Wang 	return GPIO_LINE_DIRECTION_OUT;
83*0bd459ddSShenwei Wang }
84*0bd459ddSShenwei Wang 
85*0bd459ddSShenwei Wang static int imx_scu_gpio_probe(struct platform_device *pdev)
86*0bd459ddSShenwei Wang {
87*0bd459ddSShenwei Wang 	struct device *dev = &pdev->dev;
88*0bd459ddSShenwei Wang 	struct scu_gpio_priv *priv;
89*0bd459ddSShenwei Wang 	struct gpio_chip *gc;
90*0bd459ddSShenwei Wang 	int ret;
91*0bd459ddSShenwei Wang 
92*0bd459ddSShenwei Wang 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
93*0bd459ddSShenwei Wang 	if (!priv)
94*0bd459ddSShenwei Wang 		return -ENOMEM;
95*0bd459ddSShenwei Wang 
96*0bd459ddSShenwei Wang 	ret = imx_scu_get_handle(&priv->handle);
97*0bd459ddSShenwei Wang 	if (ret)
98*0bd459ddSShenwei Wang 		return ret;
99*0bd459ddSShenwei Wang 
100*0bd459ddSShenwei Wang 	priv->dev = dev;
101*0bd459ddSShenwei Wang 	mutex_init(&priv->lock);
102*0bd459ddSShenwei Wang 
103*0bd459ddSShenwei Wang 	gc = &priv->chip;
104*0bd459ddSShenwei Wang 	gc->base = -1;
105*0bd459ddSShenwei Wang 	gc->parent = dev;
106*0bd459ddSShenwei Wang 	gc->ngpio = sizeof(scu_rsrc_arr)/sizeof(unsigned int);
107*0bd459ddSShenwei Wang 	gc->label = dev_name(dev);
108*0bd459ddSShenwei Wang 	gc->get = imx_scu_gpio_get;
109*0bd459ddSShenwei Wang 	gc->set = imx_scu_gpio_set;
110*0bd459ddSShenwei Wang 	gc->get_direction = imx_scu_gpio_get_direction;
111*0bd459ddSShenwei Wang 
112*0bd459ddSShenwei Wang 	platform_set_drvdata(pdev, priv);
113*0bd459ddSShenwei Wang 
114*0bd459ddSShenwei Wang 	return devm_gpiochip_add_data(dev, gc, priv);
115*0bd459ddSShenwei Wang }
116*0bd459ddSShenwei Wang 
117*0bd459ddSShenwei Wang static const struct of_device_id imx_scu_gpio_dt_ids[] = {
118*0bd459ddSShenwei Wang 	{ .compatible = "fsl,imx8qxp-sc-gpio" },
119*0bd459ddSShenwei Wang 	{ /* sentinel */ }
120*0bd459ddSShenwei Wang };
121*0bd459ddSShenwei Wang 
122*0bd459ddSShenwei Wang static struct platform_driver imx_scu_gpio_driver = {
123*0bd459ddSShenwei Wang 	.driver	= {
124*0bd459ddSShenwei Wang 		.name = "gpio-imx-scu",
125*0bd459ddSShenwei Wang 		.of_match_table = imx_scu_gpio_dt_ids,
126*0bd459ddSShenwei Wang 	},
127*0bd459ddSShenwei Wang 	.probe = imx_scu_gpio_probe,
128*0bd459ddSShenwei Wang };
129*0bd459ddSShenwei Wang 
130*0bd459ddSShenwei Wang static int __init _imx_scu_gpio_init(void)
131*0bd459ddSShenwei Wang {
132*0bd459ddSShenwei Wang 	return platform_driver_register(&imx_scu_gpio_driver);
133*0bd459ddSShenwei Wang }
134*0bd459ddSShenwei Wang 
135*0bd459ddSShenwei Wang subsys_initcall_sync(_imx_scu_gpio_init);
136*0bd459ddSShenwei Wang 
137*0bd459ddSShenwei Wang MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>");
138*0bd459ddSShenwei Wang MODULE_DESCRIPTION("NXP GPIO over IMX SCU API");
139*0bd459ddSShenwei Wang MODULE_LICENSE("GPL");
140