On 09/03/2020 21:37, Laurent Pinchart wrote: > The TFP410 supports configuration through I2C (in which case the > corresponding DT node is a child of an I2C controller) or through pins > (in which case the DT node creates a platform device). When I2C access > to the device is available, read and validate the device ID at probe > time to ensure that the device is present. > > While at it, sort headers alphabetically. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> > --- > This time based on drm-misc-next instead of v5.6-rc5, with conflicts > resolved. > > drivers/gpu/drm/bridge/ti-tfp410.c | 134 +++++++++++++++++++++++++---- > 1 file changed, 115 insertions(+), 19 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c > index 40c4d4a5517b..be8d74ff632b 100644 > --- a/drivers/gpu/drm/bridge/ti-tfp410.c > +++ b/drivers/gpu/drm/bridge/ti-tfp410.c > @@ -9,6 +9,7 @@ > #include <linux/module.h> > #include <linux/of_graph.h> > #include <linux/platform_device.h> > +#include <linux/regmap.h> > #include <linux/workqueue.h> > > #include <drm/drm_atomic_helper.h> > @@ -26,6 +27,7 @@ struct tfp410 { > u32 bus_format; > struct delayed_work hpd_work; > struct gpio_desc *powerdown; > + struct regmap *regmap; > > struct drm_bridge_timings timings; > struct drm_bridge *next_bridge; > @@ -213,7 +215,7 @@ static const struct drm_bridge_timings tfp410_default_timings = { > .hold_time_ps = 1300, > }; > > -static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c) > +static int tfp410_parse_timings(struct tfp410 *dvi) > { > struct drm_bridge_timings *timings = &dvi->timings; > struct device_node *ep; > @@ -224,7 +226,7 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c) > /* Start with defaults. */ > *timings = tfp410_default_timings; > > - if (i2c) > + if (dvi->regmap) > /* > * In I2C mode timings are configured through the I2C interface. > * As the driver doesn't support I2C configuration yet, we just > @@ -283,10 +285,10 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c) > return 0; > } > > -static int tfp410_init(struct device *dev, bool i2c) > +static int tfp410_init(struct tfp410 *dvi) > { > struct device_node *node; > - struct tfp410 *dvi; > + struct device *dev = dvi->dev; > int ret; > > if (!dev->of_node) { > @@ -294,11 +296,6 @@ static int tfp410_init(struct device *dev, bool i2c) > return -ENXIO; > } > > - dvi = devm_kzalloc(dev, sizeof(*dvi), GFP_KERNEL); > - if (!dvi) > - return -ENOMEM; > - > - dvi->dev = dev; > dev_set_drvdata(dev, dvi); > > dvi->bridge.funcs = &tfp410_bridge_funcs; > @@ -306,7 +303,7 @@ static int tfp410_init(struct device *dev, bool i2c) > dvi->bridge.timings = &dvi->timings; > dvi->bridge.type = DRM_MODE_CONNECTOR_DVID; > > - ret = tfp410_parse_timings(dvi, i2c); > + ret = tfp410_parse_timings(dvi); > if (ret) > return ret; > > @@ -346,7 +343,15 @@ static int tfp410_fini(struct device *dev) > > static int tfp410_probe(struct platform_device *pdev) > { > - return tfp410_init(&pdev->dev, false); > + struct tfp410 *dvi; > + > + dvi = devm_kzalloc(&pdev->dev, sizeof(*dvi), GFP_KERNEL); > + if (!dvi) > + return -ENOMEM; > + > + dvi->dev = &pdev->dev; > + > + return tfp410_init(dvi); > } > > static int tfp410_remove(struct platform_device *pdev) > @@ -370,20 +375,111 @@ static struct platform_driver tfp410_platform_driver = { > }; > > #if IS_ENABLED(CONFIG_I2C) > -/* There is currently no i2c functionality. */ > + > +#define TFP410_VEN_ID_LO 0x00 > +#define TFP410_VEN_ID_HI 0x01 > +#define TFP410_DEV_ID_LO 0x02 > +#define TFP410_DEV_ID_HI 0x03 > +#define TFP410_REV_ID 0x04 > +#define TFP410_CTL_1_MODE 0x08 > +#define TFP410_CTL_2_MODE 0x09 > +#define TFP410_CTL_3_MODE 0x0a > +#define TFP410_CFG 0x0b > +#define TFP410_DE_DLY 0x32 > +#define TFP410_DE_CTL 0x33 > +#define TFP410_DE_TOP 0x34 > +#define TFP410_DE_CNT_LO 0x36 > +#define TFP410_DE_CNT_HI 0x37 > +#define TFP410_DE_LIN_LO 0x38 > +#define TFP410_DE_LIN_HI 0x39 > +#define TFP410_H_RES_LO 0x3a > +#define TFP410_H_RES_HI 0x3b > +#define TFP410_V_RES_LO 0x3c > +#define TFP410_V_RES_HI 0x3d > + > +static const struct regmap_config tfp410_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > + > + .max_register = 0x3d, > + .wr_table = &(const struct regmap_access_table) { > + .yes_ranges = (const struct regmap_range[]) { > + { > + .range_min = TFP410_CTL_1_MODE, > + .range_max = TFP410_DE_LIN_HI, > + }, > + }, > + .n_yes_ranges = 1, > + }, > +}; > + > +static int tfp410_check_version(struct tfp410 *dvi) > +{ > + unsigned int value; > + u16 vendor_id; > + u16 device_id; > + u8 revision_id; > + int ret; > + > + ret = regmap_read(dvi->regmap, TFP410_VEN_ID_LO, &value); > + if (ret < 0) > + return ret; > + vendor_id = value; > + > + ret = regmap_read(dvi->regmap, TFP410_VEN_ID_HI, &value); > + if (ret < 0) > + return ret; > + vendor_id |= value << 8; > + > + ret = regmap_read(dvi->regmap, TFP410_DEV_ID_LO, &value); > + if (ret < 0) > + return ret; > + device_id = value; > + > + ret = regmap_read(dvi->regmap, TFP410_DEV_ID_HI, &value); > + if (ret < 0) > + return ret; > + device_id |= value << 8; > + > + ret = regmap_read(dvi->regmap, TFP410_REV_ID, &value); > + if (ret < 0) > + return ret; > + revision_id = value; > + > + if (vendor_id != 0x014c || device_id != 0x0410) { > + dev_err(dvi->dev, "invalid device ID %04x:%04x\n", > + vendor_id, device_id); > + return -ENODEV; > + } > + > + dev_info(dvi->dev, "Found TFP410 revision 0x%02x\n", revision_id); > + > + return 0; > +} > + > static int tfp410_i2c_probe(struct i2c_client *client, > const struct i2c_device_id *id) > { > - int reg; > + struct tfp410 *dvi; > + int ret; > > - if (!client->dev.of_node || > - of_property_read_u32(client->dev.of_node, "reg", ®)) { > - dev_err(&client->dev, > - "Can't get i2c reg property from device-tree\n"); > - return -ENXIO; > + dvi = devm_kzalloc(&client->dev, sizeof(*dvi), GFP_KERNEL); > + if (!dvi) > + return -ENOMEM; > + > + dvi->dev = &client->dev; > + > + dvi->regmap = devm_regmap_init_i2c(client, &tfp410_regmap_config); > + if (IS_ERR(dvi->regmap)) > + return PTR_ERR(dvi->regmap); > + > + ret = tfp410_check_version(dvi); > + if (ret < 0) { > + dev_err(dvi->dev, "failed to read device ID (%d)\n", ret); > + return ret; > } > > - return tfp410_init(&client->dev, true); > + return tfp410_init(dvi); > } > > static int tfp410_i2c_remove(struct i2c_client *client) > Reviewed-by: Neil Armstrong <narmstrong@xxxxxxxxxxxx> Neil _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel