xref: /linux/drivers/gpio/gpio-waveshare-dsi.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
1*79f44c8aSDmitry Baryshkov // SPDX-License-Identifier: GPL-2.0
2*79f44c8aSDmitry Baryshkov /*
3*79f44c8aSDmitry Baryshkov  * Copyright (C) 2024 Waveshare International Limited
4*79f44c8aSDmitry Baryshkov  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5*79f44c8aSDmitry Baryshkov  */
6*79f44c8aSDmitry Baryshkov 
7*79f44c8aSDmitry Baryshkov #include <linux/backlight.h>
8*79f44c8aSDmitry Baryshkov #include <linux/err.h>
9*79f44c8aSDmitry Baryshkov #include <linux/fb.h>
10*79f44c8aSDmitry Baryshkov #include <linux/gpio/driver.h>
11*79f44c8aSDmitry Baryshkov #include <linux/module.h>
12*79f44c8aSDmitry Baryshkov #include <linux/of.h>
13*79f44c8aSDmitry Baryshkov #include <linux/regmap.h>
14*79f44c8aSDmitry Baryshkov 
15*79f44c8aSDmitry Baryshkov /* I2C registers of the microcontroller. */
16*79f44c8aSDmitry Baryshkov #define REG_TP		0x94
17*79f44c8aSDmitry Baryshkov #define REG_LCD		0x95
18*79f44c8aSDmitry Baryshkov #define REG_PWM		0x96
19*79f44c8aSDmitry Baryshkov #define REG_SIZE	0x97
20*79f44c8aSDmitry Baryshkov #define REG_ID		0x98
21*79f44c8aSDmitry Baryshkov #define REG_VERSION	0x99
22*79f44c8aSDmitry Baryshkov 
23*79f44c8aSDmitry Baryshkov enum {
24*79f44c8aSDmitry Baryshkov 	GPIO_AVDD = 0,
25*79f44c8aSDmitry Baryshkov 	GPIO_PANEL_RESET = 1,
26*79f44c8aSDmitry Baryshkov 	GPIO_BL_ENABLE = 2,
27*79f44c8aSDmitry Baryshkov 	GPIO_IOVCC = 4,
28*79f44c8aSDmitry Baryshkov 	GPIO_VCC = 8,
29*79f44c8aSDmitry Baryshkov 	GPIO_TS_RESET = 9,
30*79f44c8aSDmitry Baryshkov };
31*79f44c8aSDmitry Baryshkov 
32*79f44c8aSDmitry Baryshkov #define NUM_GPIO 16
33*79f44c8aSDmitry Baryshkov 
34*79f44c8aSDmitry Baryshkov struct waveshare_gpio {
35*79f44c8aSDmitry Baryshkov 	struct mutex dir_lock;
36*79f44c8aSDmitry Baryshkov 	struct mutex pwr_lock;
37*79f44c8aSDmitry Baryshkov 	struct regmap *regmap;
38*79f44c8aSDmitry Baryshkov 	u16 poweron_state;
39*79f44c8aSDmitry Baryshkov 
40*79f44c8aSDmitry Baryshkov 	struct gpio_chip gc;
41*79f44c8aSDmitry Baryshkov };
42*79f44c8aSDmitry Baryshkov 
43*79f44c8aSDmitry Baryshkov static const struct regmap_config waveshare_gpio_regmap_config = {
44*79f44c8aSDmitry Baryshkov 	.reg_bits = 8,
45*79f44c8aSDmitry Baryshkov 	.val_bits = 8,
46*79f44c8aSDmitry Baryshkov 	.max_register = REG_VERSION,
47*79f44c8aSDmitry Baryshkov };
48*79f44c8aSDmitry Baryshkov 
49*79f44c8aSDmitry Baryshkov static int waveshare_gpio_get(struct waveshare_gpio *state, unsigned int offset)
50*79f44c8aSDmitry Baryshkov {
51*79f44c8aSDmitry Baryshkov 	u16 pwr_state;
52*79f44c8aSDmitry Baryshkov 
53*79f44c8aSDmitry Baryshkov 	guard(mutex)(&state->pwr_lock);
54*79f44c8aSDmitry Baryshkov 	pwr_state = state->poweron_state & BIT(offset);
55*79f44c8aSDmitry Baryshkov 
56*79f44c8aSDmitry Baryshkov 	return !!pwr_state;
57*79f44c8aSDmitry Baryshkov }
58*79f44c8aSDmitry Baryshkov 
59*79f44c8aSDmitry Baryshkov static int waveshare_gpio_set(struct waveshare_gpio *state, unsigned int offset, int value)
60*79f44c8aSDmitry Baryshkov {
61*79f44c8aSDmitry Baryshkov 	u16 last_val;
62*79f44c8aSDmitry Baryshkov 	int err;
63*79f44c8aSDmitry Baryshkov 
64*79f44c8aSDmitry Baryshkov 	guard(mutex)(&state->pwr_lock);
65*79f44c8aSDmitry Baryshkov 
66*79f44c8aSDmitry Baryshkov 	last_val = state->poweron_state;
67*79f44c8aSDmitry Baryshkov 	if (value)
68*79f44c8aSDmitry Baryshkov 		last_val |= BIT(offset);
69*79f44c8aSDmitry Baryshkov 	else
70*79f44c8aSDmitry Baryshkov 		last_val &= ~BIT(offset);
71*79f44c8aSDmitry Baryshkov 
72*79f44c8aSDmitry Baryshkov 	state->poweron_state = last_val;
73*79f44c8aSDmitry Baryshkov 
74*79f44c8aSDmitry Baryshkov 	err = regmap_write(state->regmap, REG_TP, last_val >> 8);
75*79f44c8aSDmitry Baryshkov 	if (!err)
76*79f44c8aSDmitry Baryshkov 		err = regmap_write(state->regmap, REG_LCD, last_val & 0xff);
77*79f44c8aSDmitry Baryshkov 
78*79f44c8aSDmitry Baryshkov 	return err;
79*79f44c8aSDmitry Baryshkov }
80*79f44c8aSDmitry Baryshkov 
81*79f44c8aSDmitry Baryshkov static int waveshare_gpio_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
82*79f44c8aSDmitry Baryshkov {
83*79f44c8aSDmitry Baryshkov 	return GPIO_LINE_DIRECTION_OUT;
84*79f44c8aSDmitry Baryshkov }
85*79f44c8aSDmitry Baryshkov 
86*79f44c8aSDmitry Baryshkov static int waveshare_gpio_gpio_get(struct gpio_chip *gc, unsigned int offset)
87*79f44c8aSDmitry Baryshkov {
88*79f44c8aSDmitry Baryshkov 	struct waveshare_gpio *state = gpiochip_get_data(gc);
89*79f44c8aSDmitry Baryshkov 
90*79f44c8aSDmitry Baryshkov 	return waveshare_gpio_get(state, offset);
91*79f44c8aSDmitry Baryshkov }
92*79f44c8aSDmitry Baryshkov 
93*79f44c8aSDmitry Baryshkov static int waveshare_gpio_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
94*79f44c8aSDmitry Baryshkov {
95*79f44c8aSDmitry Baryshkov 	struct waveshare_gpio *state = gpiochip_get_data(gc);
96*79f44c8aSDmitry Baryshkov 
97*79f44c8aSDmitry Baryshkov 	return waveshare_gpio_set(state, offset, value);
98*79f44c8aSDmitry Baryshkov }
99*79f44c8aSDmitry Baryshkov 
100*79f44c8aSDmitry Baryshkov static int waveshare_gpio_update_status(struct backlight_device *bl)
101*79f44c8aSDmitry Baryshkov {
102*79f44c8aSDmitry Baryshkov 	struct waveshare_gpio *state = bl_get_data(bl);
103*79f44c8aSDmitry Baryshkov 	int brightness = backlight_get_brightness(bl);
104*79f44c8aSDmitry Baryshkov 
105*79f44c8aSDmitry Baryshkov 	waveshare_gpio_set(state, GPIO_BL_ENABLE, brightness);
106*79f44c8aSDmitry Baryshkov 
107*79f44c8aSDmitry Baryshkov 	return regmap_write(state->regmap, REG_PWM, brightness);
108*79f44c8aSDmitry Baryshkov }
109*79f44c8aSDmitry Baryshkov 
110*79f44c8aSDmitry Baryshkov static const struct backlight_ops waveshare_gpio_bl = {
111*79f44c8aSDmitry Baryshkov 	.update_status = waveshare_gpio_update_status,
112*79f44c8aSDmitry Baryshkov };
113*79f44c8aSDmitry Baryshkov 
114*79f44c8aSDmitry Baryshkov static int waveshare_gpio_probe(struct i2c_client *i2c)
115*79f44c8aSDmitry Baryshkov {
116*79f44c8aSDmitry Baryshkov 	struct backlight_properties props = {};
117*79f44c8aSDmitry Baryshkov 	struct waveshare_gpio *state;
118*79f44c8aSDmitry Baryshkov 	struct device *dev = &i2c->dev;
119*79f44c8aSDmitry Baryshkov 	struct backlight_device *bl;
120*79f44c8aSDmitry Baryshkov 	struct regmap *regmap;
121*79f44c8aSDmitry Baryshkov 	unsigned int data;
122*79f44c8aSDmitry Baryshkov 	int ret;
123*79f44c8aSDmitry Baryshkov 
124*79f44c8aSDmitry Baryshkov 	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
125*79f44c8aSDmitry Baryshkov 	if (!state)
126*79f44c8aSDmitry Baryshkov 		return -ENOMEM;
127*79f44c8aSDmitry Baryshkov 
128*79f44c8aSDmitry Baryshkov 	ret = devm_mutex_init(dev, &state->dir_lock);
129*79f44c8aSDmitry Baryshkov 	if (ret)
130*79f44c8aSDmitry Baryshkov 		return ret;
131*79f44c8aSDmitry Baryshkov 
132*79f44c8aSDmitry Baryshkov 	ret = devm_mutex_init(dev, &state->pwr_lock);
133*79f44c8aSDmitry Baryshkov 	if (ret)
134*79f44c8aSDmitry Baryshkov 		return ret;
135*79f44c8aSDmitry Baryshkov 
136*79f44c8aSDmitry Baryshkov 	regmap = devm_regmap_init_i2c(i2c, &waveshare_gpio_regmap_config);
137*79f44c8aSDmitry Baryshkov 	if (IS_ERR(regmap))
138*79f44c8aSDmitry Baryshkov 		return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate register map\n");
139*79f44c8aSDmitry Baryshkov 
140*79f44c8aSDmitry Baryshkov 	state->regmap = regmap;
141*79f44c8aSDmitry Baryshkov 	i2c_set_clientdata(i2c, state);
142*79f44c8aSDmitry Baryshkov 
143*79f44c8aSDmitry Baryshkov 	ret = regmap_read(regmap, REG_ID, &data);
144*79f44c8aSDmitry Baryshkov 	if (ret < 0)
145*79f44c8aSDmitry Baryshkov 		return dev_err_probe(dev, ret, "Failed to read register\n");
146*79f44c8aSDmitry Baryshkov 
147*79f44c8aSDmitry Baryshkov 	dev_dbg(dev, "waveshare panel hw id = 0x%x\n", data);
148*79f44c8aSDmitry Baryshkov 
149*79f44c8aSDmitry Baryshkov 	ret = regmap_read(regmap, REG_SIZE, &data);
150*79f44c8aSDmitry Baryshkov 	if (ret < 0)
151*79f44c8aSDmitry Baryshkov 		return dev_err_probe(dev, ret, "Failed to read register\n");
152*79f44c8aSDmitry Baryshkov 
153*79f44c8aSDmitry Baryshkov 	dev_dbg(dev, "waveshare panel size = %d\n", data);
154*79f44c8aSDmitry Baryshkov 
155*79f44c8aSDmitry Baryshkov 	ret = regmap_read(regmap, REG_VERSION, &data);
156*79f44c8aSDmitry Baryshkov 	if (ret < 0)
157*79f44c8aSDmitry Baryshkov 		return dev_err_probe(dev, ret, "Failed to read register\n");
158*79f44c8aSDmitry Baryshkov 
159*79f44c8aSDmitry Baryshkov 	dev_dbg(dev, "waveshare panel mcu version = 0x%x\n", data);
160*79f44c8aSDmitry Baryshkov 
161*79f44c8aSDmitry Baryshkov 	ret = waveshare_gpio_set(state, GPIO_TS_RESET, 1);
162*79f44c8aSDmitry Baryshkov 	if (ret)
163*79f44c8aSDmitry Baryshkov 		return dev_err_probe(dev, ret, "Failed to program GPIOs\n");
164*79f44c8aSDmitry Baryshkov 
165*79f44c8aSDmitry Baryshkov 	msleep(20);
166*79f44c8aSDmitry Baryshkov 
167*79f44c8aSDmitry Baryshkov 	state->gc.parent = dev;
168*79f44c8aSDmitry Baryshkov 	state->gc.label = i2c->name;
169*79f44c8aSDmitry Baryshkov 	state->gc.owner = THIS_MODULE;
170*79f44c8aSDmitry Baryshkov 	state->gc.base = -1;
171*79f44c8aSDmitry Baryshkov 	state->gc.ngpio = NUM_GPIO;
172*79f44c8aSDmitry Baryshkov 
173*79f44c8aSDmitry Baryshkov 	/* it is output only */
174*79f44c8aSDmitry Baryshkov 	state->gc.get = waveshare_gpio_gpio_get;
175*79f44c8aSDmitry Baryshkov 	state->gc.set = waveshare_gpio_gpio_set;
176*79f44c8aSDmitry Baryshkov 	state->gc.get_direction = waveshare_gpio_gpio_get_direction;
177*79f44c8aSDmitry Baryshkov 	state->gc.can_sleep = true;
178*79f44c8aSDmitry Baryshkov 
179*79f44c8aSDmitry Baryshkov 	ret = devm_gpiochip_add_data(dev, &state->gc, state);
180*79f44c8aSDmitry Baryshkov 	if (ret)
181*79f44c8aSDmitry Baryshkov 		return dev_err_probe(dev, ret, "Failed to create gpiochip\n");
182*79f44c8aSDmitry Baryshkov 
183*79f44c8aSDmitry Baryshkov 	props.type = BACKLIGHT_RAW;
184*79f44c8aSDmitry Baryshkov 	props.max_brightness = 255;
185*79f44c8aSDmitry Baryshkov 	props.brightness = 255;
186*79f44c8aSDmitry Baryshkov 	bl = devm_backlight_device_register(dev, dev_name(dev), dev, state,
187*79f44c8aSDmitry Baryshkov 					    &waveshare_gpio_bl, &props);
188*79f44c8aSDmitry Baryshkov 	return PTR_ERR_OR_ZERO(bl);
189*79f44c8aSDmitry Baryshkov }
190*79f44c8aSDmitry Baryshkov 
191*79f44c8aSDmitry Baryshkov static const struct of_device_id waveshare_gpio_dt_ids[] = {
192*79f44c8aSDmitry Baryshkov 	{ .compatible = "waveshare,dsi-touch-gpio" },
193*79f44c8aSDmitry Baryshkov 	{},
194*79f44c8aSDmitry Baryshkov };
195*79f44c8aSDmitry Baryshkov MODULE_DEVICE_TABLE(of, waveshare_gpio_dt_ids);
196*79f44c8aSDmitry Baryshkov 
197*79f44c8aSDmitry Baryshkov static struct i2c_driver waveshare_gpio_regulator_driver = {
198*79f44c8aSDmitry Baryshkov 	.driver = {
199*79f44c8aSDmitry Baryshkov 		.name = "waveshare-regulator",
200*79f44c8aSDmitry Baryshkov 		.of_match_table = of_match_ptr(waveshare_gpio_dt_ids),
201*79f44c8aSDmitry Baryshkov 	},
202*79f44c8aSDmitry Baryshkov 	.probe = waveshare_gpio_probe,
203*79f44c8aSDmitry Baryshkov };
204*79f44c8aSDmitry Baryshkov 
205*79f44c8aSDmitry Baryshkov module_i2c_driver(waveshare_gpio_regulator_driver);
206*79f44c8aSDmitry Baryshkov 
207*79f44c8aSDmitry Baryshkov MODULE_DESCRIPTION("GPIO controller driver for Waveshare DSI touch panels");
208*79f44c8aSDmitry Baryshkov MODULE_LICENSE("GPL");
209