1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Driver for Sitronix ST7571 connected via I2C bus.
4 *
5 * Copyright (C) 2025 Marcus Folkesson <marcus.folkesson@gmail.com>
6 */
7
8 #include <linux/i2c.h>
9 #include <linux/module.h>
10 #include <linux/regmap.h>
11
12 #include "st7571.h"
13
14 struct st7571_i2c_transport {
15 struct i2c_client *client;
16
17 /*
18 * Depending on the hardware design, the acknowledge signal may be hard to
19 * recognize as a valid logic "0" level.
20 * Therefor, ignore NAK if possible to stay compatible with most hardware designs
21 * and off-the-shelf panels out there.
22 *
23 * From section 6.4 MICROPOCESSOR INTERFACE section in the datasheet:
24 *
25 * "By connecting SDA_OUT to SDA_IN externally, the SDA line becomes fully
26 * I2C interface compatible.
27 * Separating acknowledge-output from serial data
28 * input is advantageous for chip-on-glass (COG) applications. In COG
29 * applications, the ITO resistance and the pull-up resistor will form a
30 * voltage divider, which affects acknowledge-signal level. Larger ITO
31 * resistance will raise the acknowledged-signal level and system cannot
32 * recognize this level as a valid logic “0” level. By separating SDA_IN from
33 * SDA_OUT, the IC can be used in a mode that ignores the acknowledge-bit.
34 * For applications which check acknowledge-bit, it is necessary to minimize
35 * the ITO resistance of the SDA_OUT trace to guarantee a valid low level."
36 *
37 */
38 bool ignore_nak;
39 };
40
st7571_i2c_regmap_write(void * context,const void * data,size_t count)41 static int st7571_i2c_regmap_write(void *context, const void *data, size_t count)
42 {
43 struct st7571_i2c_transport *t = context;
44 int ret;
45
46 struct i2c_msg msg = {
47 .addr = t->client->addr,
48 .flags = t->ignore_nak ? I2C_M_IGNORE_NAK : 0,
49 .len = count,
50 .buf = (u8 *)data
51 };
52
53 ret = i2c_transfer(t->client->adapter, &msg, 1);
54
55 /*
56 * Unfortunately, there is no way to check if the transfer failed because of
57 * a NAK or something else as I2C bus drivers use different return values for NAK.
58 *
59 * However, if the transfer fails and ignore_nak is set, we know it is an error.
60 */
61 if (ret < 0 && t->ignore_nak)
62 return ret;
63
64 return 0;
65 }
66
67 /* The st7571 driver does not read registers but regmap expects a .read */
st7571_i2c_regmap_read(void * context,const void * reg_buf,size_t reg_size,void * val_buf,size_t val_size)68 static int st7571_i2c_regmap_read(void *context, const void *reg_buf,
69 size_t reg_size, void *val_buf, size_t val_size)
70 {
71 return -EOPNOTSUPP;
72 }
73
74 static const struct regmap_bus st7571_i2c_regmap_bus = {
75 .read = st7571_i2c_regmap_read,
76 .write = st7571_i2c_regmap_write,
77 };
78
79 static const struct regmap_config st7571_i2c_regmap_config = {
80 .reg_bits = 8,
81 .val_bits = 8,
82 .use_single_write = true,
83 };
84
st7571_i2c_probe(struct i2c_client * client)85 static int st7571_i2c_probe(struct i2c_client *client)
86 {
87 struct st7571_device *st7571;
88 struct st7571_i2c_transport *t;
89 struct regmap *regmap;
90
91 t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
92 if (!t)
93 return -ENOMEM;
94
95 t->client = client;
96
97 /*
98 * The hardware design could make it hard to detect a NAK on the I2C bus.
99 * If the adapter does not support protocol mangling do
100 * not set the I2C_M_IGNORE_NAK flag at the expense * of possible
101 * cruft in the logs.
102 */
103 if (i2c_check_functionality(client->adapter, I2C_FUNC_PROTOCOL_MANGLING))
104 t->ignore_nak = true;
105
106 regmap = devm_regmap_init(&client->dev, &st7571_i2c_regmap_bus,
107 t, &st7571_i2c_regmap_config);
108 if (IS_ERR(regmap)) {
109 return dev_err_probe(&client->dev, PTR_ERR(regmap),
110 "Failed to initialize regmap\n");
111 }
112
113 st7571 = st7571_probe(&client->dev, regmap);
114 if (IS_ERR(st7571))
115 return dev_err_probe(&client->dev, PTR_ERR(st7571),
116 "Failed to initialize regmap\n");
117
118 i2c_set_clientdata(client, st7571);
119 return 0;
120 }
121
st7571_i2c_remove(struct i2c_client * client)122 static void st7571_i2c_remove(struct i2c_client *client)
123 {
124 struct st7571_device *st7571 = i2c_get_clientdata(client);
125
126 st7571_remove(st7571);
127 }
128
129 static const struct of_device_id st7571_of_match[] = {
130 { .compatible = "sitronix,st7567", .data = &st7567_config },
131 { .compatible = "sitronix,st7571", .data = &st7571_config },
132 {},
133 };
134 MODULE_DEVICE_TABLE(of, st7571_of_match);
135
136 static const struct i2c_device_id st7571_id[] = {
137 { "st7567", 0 },
138 { "st7571", 0 },
139 { }
140 };
141 MODULE_DEVICE_TABLE(i2c, st7571_id);
142
143 static struct i2c_driver st7571_i2c_driver = {
144 .driver = {
145 .name = "st7571-i2c",
146 .of_match_table = st7571_of_match,
147 },
148 .probe = st7571_i2c_probe,
149 .remove = st7571_i2c_remove,
150 .id_table = st7571_id,
151 };
152
153 module_i2c_driver(st7571_i2c_driver);
154
155 MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
156 MODULE_DESCRIPTION("DRM Driver for Sitronix ST7571 LCD controller (I2C)");
157 MODULE_LICENSE("GPL");
158 MODULE_IMPORT_NS("DRM_ST7571");
159