mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 17:13:52 +02:00
drm/sitronix/st7571-i2c: make probe independent of hw interface
Create an interface independent layer for the probe function. This is to make it possible to add support for other interfaces. Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com> Link: https://patch.msgid.link/20251215-st7571-split-v3-4-d5f3205c3138@gmail.com Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
This commit is contained in:
parent
d93a435468
commit
b0c20d827e
|
|
@ -80,6 +80,33 @@
|
|||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 0
|
||||
|
||||
struct st7571_i2c_transport {
|
||||
struct i2c_client *client;
|
||||
|
||||
/*
|
||||
* Depending on the hardware design, the acknowledge signal may be hard to
|
||||
* recognize as a valid logic "0" level.
|
||||
* Therefor, ignore NAK if possible to stay compatible with most hardware designs
|
||||
* and off-the-shelf panels out there.
|
||||
*
|
||||
* From section 6.4 MICROPOCESSOR INTERFACE section in the datasheet:
|
||||
*
|
||||
* "By connecting SDA_OUT to SDA_IN externally, the SDA line becomes fully
|
||||
* I2C interface compatible.
|
||||
* Separating acknowledge-output from serial data
|
||||
* input is advantageous for chip-on-glass (COG) applications. In COG
|
||||
* applications, the ITO resistance and the pull-up resistor will form a
|
||||
* voltage divider, which affects acknowledge-signal level. Larger ITO
|
||||
* resistance will raise the acknowledged-signal level and system cannot
|
||||
* recognize this level as a valid logic “0” level. By separating SDA_IN from
|
||||
* SDA_OUT, the IC can be used in a mode that ignores the acknowledge-bit.
|
||||
* For applications which check acknowledge-bit, it is necessary to minimize
|
||||
* the ITO resistance of the SDA_OUT trace to guarantee a valid low level."
|
||||
*
|
||||
*/
|
||||
bool ignore_nak;
|
||||
};
|
||||
|
||||
static inline struct st7571_device *drm_to_st7571(struct drm_device *drm)
|
||||
{
|
||||
return container_of(drm, struct st7571_device, drm);
|
||||
|
|
@ -87,18 +114,17 @@ static inline struct st7571_device *drm_to_st7571(struct drm_device *drm)
|
|||
|
||||
static int st7571_regmap_write(void *context, const void *data, size_t count)
|
||||
{
|
||||
struct i2c_client *client = context;
|
||||
struct st7571_device *st7571 = i2c_get_clientdata(client);
|
||||
struct st7571_i2c_transport *t = context;
|
||||
int ret;
|
||||
|
||||
struct i2c_msg msg = {
|
||||
.addr = st7571->client->addr,
|
||||
.flags = st7571->ignore_nak ? I2C_M_IGNORE_NAK : 0,
|
||||
.addr = t->client->addr,
|
||||
.flags = t->ignore_nak ? I2C_M_IGNORE_NAK : 0,
|
||||
.len = count,
|
||||
.buf = (u8 *)data
|
||||
};
|
||||
|
||||
ret = i2c_transfer(st7571->client->adapter, &msg, 1);
|
||||
ret = i2c_transfer(t->client->adapter, &msg, 1);
|
||||
|
||||
/*
|
||||
* Unfortunately, there is no way to check if the transfer failed because of
|
||||
|
|
@ -106,7 +132,7 @@ static int st7571_regmap_write(void *context, const void *data, size_t count)
|
|||
*
|
||||
* However, if the transfer fails and ignore_nak is set, we know it is an error.
|
||||
*/
|
||||
if (ret < 0 && st7571->ignore_nak)
|
||||
if (ret < 0 && t->ignore_nak)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
|
@ -845,32 +871,104 @@ static int st7571_lcd_init(struct st7571_device *st7571)
|
|||
return st7571_send_command_list(st7571, commands, ARRAY_SIZE(commands));
|
||||
}
|
||||
|
||||
static int st7571_probe(struct i2c_client *client)
|
||||
static struct st7571_device *st7571_probe(struct device *dev,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
struct st7571_device *st7571;
|
||||
struct drm_device *drm;
|
||||
int ret;
|
||||
|
||||
st7571 = devm_drm_dev_alloc(&client->dev, &st7571_driver,
|
||||
st7571 = devm_drm_dev_alloc(dev, &st7571_driver,
|
||||
struct st7571_device, drm);
|
||||
if (IS_ERR(st7571))
|
||||
return PTR_ERR(st7571);
|
||||
return st7571;
|
||||
|
||||
drm = &st7571->drm;
|
||||
st7571->dev = &client->dev;
|
||||
st7571->client = client;
|
||||
i2c_set_clientdata(client, st7571);
|
||||
st7571->dev = dev;
|
||||
st7571->pdata = device_get_match_data(st7571->dev);
|
||||
|
||||
ret = st7571->pdata->parse_dt(st7571);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = st7571_validate_parameters(st7571);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
|
||||
st7571->mode = st7571_mode(st7571);
|
||||
st7571->regmap = regmap;
|
||||
|
||||
|
||||
st7571->hwbuf = devm_kzalloc(st7571->dev,
|
||||
(st7571->nlines * st7571->ncols * st7571->bpp) / 8,
|
||||
GFP_KERNEL);
|
||||
if (!st7571->hwbuf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
st7571->row = devm_kzalloc(st7571->dev,
|
||||
(st7571->ncols * st7571->bpp),
|
||||
GFP_KERNEL);
|
||||
if (!st7571->row)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = st7571_mode_config_init(st7571);
|
||||
if (ret) {
|
||||
dev_err(st7571->dev, "Failed to initialize mode config\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = st7571_plane_init(st7571, st7571->pformat);
|
||||
if (ret) {
|
||||
dev_err(st7571->dev, "Failed to initialize primary plane\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = st7571_crtc_init(st7571);
|
||||
if (ret < 0) {
|
||||
dev_err(st7571->dev, "Failed to initialize CRTC\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = st7571_encoder_init(st7571);
|
||||
if (ret < 0) {
|
||||
dev_err(st7571->dev, "Failed to initialize encoder\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = st7571_connector_init(st7571);
|
||||
if (ret < 0) {
|
||||
dev_err(st7571->dev, "Failed to initialize connector\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
ret = drm_dev_register(drm, 0);
|
||||
if (ret) {
|
||||
dev_err(st7571->dev, "Failed to register DRM device\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
drm_client_setup(drm, NULL);
|
||||
return st7571;
|
||||
}
|
||||
|
||||
static void st7571_remove(struct st7571_device *st7571)
|
||||
{
|
||||
drm_dev_unplug(&st7571->drm);
|
||||
}
|
||||
|
||||
static int st7571_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
struct st7571_device *st7571;
|
||||
struct st7571_i2c_transport *t;
|
||||
struct regmap *regmap;
|
||||
|
||||
t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
t->client = client;
|
||||
|
||||
/*
|
||||
* The hardware design could make it hard to detect a NAK on the I2C bus.
|
||||
|
|
@ -879,68 +977,29 @@ static int st7571_probe(struct i2c_client *client)
|
|||
* cruft in the logs.
|
||||
*/
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_PROTOCOL_MANGLING))
|
||||
st7571->ignore_nak = true;
|
||||
t->ignore_nak = true;
|
||||
|
||||
st7571->regmap = devm_regmap_init(st7571->dev, &st7571_regmap_bus,
|
||||
client, &st7571_regmap_config);
|
||||
if (IS_ERR(st7571->regmap)) {
|
||||
return dev_err_probe(st7571->dev, PTR_ERR(st7571->regmap),
|
||||
regmap = devm_regmap_init(&client->dev, &st7571_regmap_bus,
|
||||
t, &st7571_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
return dev_err_probe(&client->dev, PTR_ERR(regmap),
|
||||
"Failed to initialize regmap\n");
|
||||
}
|
||||
|
||||
st7571->hwbuf = devm_kzalloc(st7571->dev,
|
||||
(st7571->nlines * st7571->ncols * st7571->bpp) / 8,
|
||||
GFP_KERNEL);
|
||||
if (!st7571->hwbuf)
|
||||
return -ENOMEM;
|
||||
st7571 = st7571_probe(&client->dev, regmap);
|
||||
if (IS_ERR(st7571))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(st7571),
|
||||
"Failed to initialize regmap\n");
|
||||
|
||||
st7571->row = devm_kzalloc(st7571->dev,
|
||||
(st7571->ncols * st7571->bpp),
|
||||
GFP_KERNEL);
|
||||
if (!st7571->row)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = st7571_mode_config_init(st7571);
|
||||
if (ret)
|
||||
return dev_err_probe(st7571->dev, ret,
|
||||
"Failed to initialize mode config\n");
|
||||
|
||||
ret = st7571_plane_init(st7571, st7571->pformat);
|
||||
if (ret)
|
||||
return dev_err_probe(st7571->dev, ret,
|
||||
"Failed to initialize primary plane\n");
|
||||
|
||||
ret = st7571_crtc_init(st7571);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(st7571->dev, ret,
|
||||
"Failed to initialize CRTC\n");
|
||||
|
||||
ret = st7571_encoder_init(st7571);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(st7571->dev, ret,
|
||||
"Failed to initialize encoder\n");
|
||||
|
||||
ret = st7571_connector_init(st7571);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(st7571->dev, ret,
|
||||
"Failed to initialize connector\n");
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
ret = drm_dev_register(drm, 0);
|
||||
if (ret)
|
||||
return dev_err_probe(st7571->dev, ret,
|
||||
"Failed to register DRM device\n");
|
||||
|
||||
drm_client_setup(drm, NULL);
|
||||
i2c_set_clientdata(client, st7571);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void st7571_remove(struct i2c_client *client)
|
||||
static void st7571_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct st7571_device *st7571 = i2c_get_clientdata(client);
|
||||
|
||||
drm_dev_unplug(&st7571->drm);
|
||||
st7571_remove(st7571);
|
||||
}
|
||||
|
||||
static const struct st7571_panel_data st7567_config = {
|
||||
|
|
@ -986,8 +1045,8 @@ static struct i2c_driver st7571_i2c_driver = {
|
|||
.name = "st7571",
|
||||
.of_match_table = st7571_of_match,
|
||||
},
|
||||
.probe = st7571_probe,
|
||||
.remove = st7571_remove,
|
||||
.probe = st7571_i2c_probe,
|
||||
.remove = st7571_i2c_remove,
|
||||
.id_table = st7571_id,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
|
@ -62,33 +63,9 @@ struct st7571_device {
|
|||
|
||||
const struct st7571_panel_format *pformat;
|
||||
const struct st7571_panel_data *pdata;
|
||||
struct i2c_client *client;
|
||||
struct gpio_desc *reset;
|
||||
struct regmap *regmap;
|
||||
|
||||
/*
|
||||
* Depending on the hardware design, the acknowledge signal may be hard to
|
||||
* recognize as a valid logic "0" level.
|
||||
* Therefor, ignore NAK if possible to stay compatible with most hardware designs
|
||||
* and off-the-shelf panels out there.
|
||||
*
|
||||
* From section 6.4 MICROPOCESSOR INTERFACE section in the datasheet:
|
||||
*
|
||||
* "By connecting SDA_OUT to SDA_IN externally, the SDA line becomes fully
|
||||
* I2C interface compatible.
|
||||
* Separating acknowledge-output from serial data
|
||||
* input is advantageous for chip-on-glass (COG) applications. In COG
|
||||
* applications, the ITO resistance and the pull-up resistor will form a
|
||||
* voltage divider, which affects acknowledge-signal level. Larger ITO
|
||||
* resistance will raise the acknowledged-signal level and system cannot
|
||||
* recognize this level as a valid logic “0” level. By separating SDA_IN from
|
||||
* SDA_OUT, the IC can be used in a mode that ignores the acknowledge-bit.
|
||||
* For applications which check acknowledge-bit, it is necessary to minimize
|
||||
* the ITO resistance of the SDA_OUT trace to guarantee a valid low level."
|
||||
*
|
||||
*/
|
||||
bool ignore_nak;
|
||||
|
||||
bool grayscale;
|
||||
bool inverted;
|
||||
u32 height_mm;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user