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