Re: [PATCH V6 8/8] drm/bridge: Add i2c based driver for ps8622/ps8625 bridge

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Jul 26, 2014 at 12:52:10AM +0530, Ajay Kumar wrote:
[...]
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 46a311e..b4a99cc 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -96,6 +96,7 @@ nxp	NXP Semiconductors
>  onnn	ON Semiconductor Corp.
>  opencores	OpenCores.org
>  panasonic	Panasonic Corporation
> +parade	Parade Technologies Inc.
>  phytec	PHYTEC Messtechnik GmbH
>  picochip	Picochip Ltd
>  plathome	Plat'Home Co., Ltd.

I think it's a good idea to turn this into a separate patch to avoid
conflicts.

> diff --git a/Documentation/devicetree/bindings/video/bridge/ps8622.txt b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
> new file mode 100644
> index 0000000..fdeafb2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
> @@ -0,0 +1,19 @@
> +ps8622-bridge bindings
> +
> +Required properties:
> +	- compatible: "parade,ps8622" or "parade,ps8625"
> +	- reg: first i2c address of the bridge

I'm not sure what the deal is with devices that use more than one I2C
addresses. It would be good to hear from the device tree maintainers on
how to handle those. Technically each address is a separate device. This
is also mirrored in the Linux kernel's implementation of the I2C bus,
where it looks wrong to access more than a single address (since the
core only marks one of them used). So technically it's valid for
userspace to access any but the first "page" of this device.

> +	- sleep-gpios: OF device-tree gpio specification
> +	- reset-gpios: OF device-tree gpio specification

This should explain what these GPIOs are used for.

> +
> +Optional properties:
> +	- lane-count: number of DP lanes to use
> +
> +Example:
> +	ps8622-bridge@48 {
> +		compatible = "parade,ps8622";
> +		reg = <0x48>;
> +		sleep-gpios = <&gpc3 6 1 0 0>;
> +		reset-gpios = <&gpc3 1 1 0 0>;
> +		lane-count = <1>
> +	};

Same here. It's usually best to make this a patch separate from the
driver. Not because of conflicts, but because it makes it easier for DT
reviewers to find the relevant pieces to look at.

> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 0b12d16..d73e474 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -16,4 +16,14 @@ config DRM_PTN3460
>  	help
>  	  ptn3460 eDP-LVDS bridge chip driver.
>  
> +config DRM_PS8622
> +	tristate "Parade eDP/LVDS bridge"
> +	depends on DRM && DRM_BRIDGE

Aagin, these are unnecessary.

> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
> index b4733e1..d1b5daa 100644
> --- a/drivers/gpu/drm/bridge/Makefile
> +++ b/drivers/gpu/drm/bridge/Makefile
> @@ -1,3 +1,4 @@
>  ccflags-y := -Iinclude/drm
>  
>  obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
> +obj-$(CONFIG_DRM_PS8622) += ps8622.o

Please keep these sorted alphabetically.

> diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
[...]
> +#include <linux/module.h>
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/fb.h>
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pm.h>
> +#include <linux/regulator/consumer.h>

These too.

> +struct ps8622_bridge {
> +	struct drm_connector connector;
> +	struct i2c_client *client;
> +	struct drm_bridge *bridge;

Should be embedded.

> +	struct drm_panel *panel;
> +	struct regulator *v12;
> +	struct backlight_device *bl;
> +	struct mutex enable_mutex;

I don't quite understand what this protects. Can you explain?

> +struct ps8622_device_data {
> +	u8 max_lane_count;
> +};
> +
> +static const struct ps8622_device_data ps8622_data = {
> +	.max_lane_count = 1,
> +};
> +
> +static const struct ps8622_device_data ps8625_data = {
> +	.max_lane_count = 2,
> +};
> +
> +/* Brightness scale on the Parade chip */
> +#define PS8622_MAX_BRIGHTNESS 0xff
> +
> +/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
> +#define PS8622_POWER_RISE_T1_MIN_US 10
> +#define PS8622_POWER_RISE_T1_MAX_US 10000
> +#define PS8622_RST_HIGH_T2_MIN_US 3000
> +#define PS8622_RST_HIGH_T2_MAX_US 30000
> +#define PS8622_PWMO_END_T12_MS 200
> +#define PS8622_POWER_FALL_T16_MAX_US 10000
> +#define PS8622_POWER_OFF_T17_MS 500
> +
> +#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
> +	(PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
> +#error "T2.min + T1.max must be less than T2.max + T1.min"
> +#endif
> +
> +static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
> +{
> +	int ret;
> +	struct i2c_adapter *adap = client->adapter;
> +	struct i2c_msg msg;
> +	u8 data[] = {reg, val};
> +
> +	msg.addr = client->addr + page;
> +	msg.flags = 0;
> +	msg.len = sizeof(data);
> +	msg.buf = data;
> +
> +	ret = i2c_transfer(adap, &msg, 1);
> +	if (ret != 1)
> +		pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
> +			client->addr + page, reg, val, ret);
> +	return !(ret == 1);
> +}
> +
> +static int ps8622_send_config(struct ps8622_bridge *ps_bridge)
> +{
> +	struct i2c_client *cl = ps_bridge->client;
> +	int err = 0;
> +
> +	/* wait 20ms after power ON */
> +	usleep_range(20000, 30000);

It's unusual to do this here. The function doesn't know when it's being
called. It could theoretically be called at any point. Better to move
the sleep to after where the device is powered on.

> +
> +	err |= ps8622_set(cl, 0x02, 0xa1, 0x01); /* HPD low */
> +	/* SW setting */
> +	err |= ps8622_set(cl, 0x04, 0x14, 0x01); /* [1:0] SW output 1.2V voltage
> +						  * is lower to 96% */

I'm not at all a fan of this kind of error chaining because you loose
all context about specific errors. Also if there's a systematic error
you'll want to abort as early as possible. If the device doesn't respond
to the first command sent, then it likely won't respond to the next
either. No need to keep trying in that case.

> +	/* RCO SS setting */
> +	err |= ps8622_set(cl, 0x04, 0xe3, 0x20); /* [5:4] = b01 0.5%, b10 1%,
> +						  * b11 1.5% */

Also I find it very hard to follow these calls. Since you have enough
information about what each of these registers does, can't you provide
symbolic constants?

It would probably also help to separate these into logical groups (or
individual function calls if there are no meaningful groups). That way
you'll get automatic documentation via function names and this function
would look a lot less cluttered.

> +static int ps8622_backlight_get(struct backlight_device *bl)
> +{
> +	return bl->props.brightness;
> +}

Backlight devices no longer need this kind of trivial implementation. It
is what the backlight core will do by default if the driver doesn't
implement .get_brightness().

> +static void ps8622_pre_enable(struct drm_bridge *bridge)
> +{
> +	struct ps8622_bridge *ps_bridge = bridge->driver_private;
> +	int ret;
> +
> +	mutex_lock(&ps_bridge->enable_mutex);
> +	if (ps_bridge->enabled)
> +		goto out;
> +
> +	gpiod_set_value(ps_bridge->gpio_rst_n, 0);
> +
> +	if (ps_bridge->v12) {
> +		ret = regulator_enable(ps_bridge->v12);
> +		if (ret)
> +			DRM_ERROR("fails to enable ps_bridge->v12");
> +	}
> +
> +	drm_panel_prepare(ps_bridge->panel);
> +
> +	gpiod_set_value(ps_bridge->gpio_slp_n, 1);

This uses high-active logic for the sleep pin, so shouldn't it rather be
named "gpio_slp"?

> +	/*
> +	 * T1 is the range of time that it takes for the power to rise after we
> +	 * enable the lcd fet.

Is that the time it takes for the FET's power to rise? In that case it
would be a property of the FET, not the bridge.

>                              T2 is the range of time in which the data sheet
> +	 * specifies we should deassert the reset pin.
> +	 *
> +	 * If it takes T1.max for the power to rise, we need to wait atleast
> +	 * T2.min before deasserting the reset pin. If it takes T1.min for the
> +	 * power to rise, we need to wait at most T2.max before deasserting the
> +	 * reset pin.
> +	 */

Note that to my knowledge none of the sleep functions give you any
guarantees about the maximum amount of time they'll sleep, only the
minimum. So there's no such thing as "wait at most" in Linux.

> +	usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
> +		     PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
> +
> +	gpiod_set_value(ps_bridge->gpio_rst_n, 1);

This also uses high-active logic.

> +	ret = ps8622_send_config(ps_bridge);
> +	if (ret)
> +		DRM_ERROR("Failed to send config to bridge (%d)\n", ret);

Isn't this a fatal error? What will be the consequences if this doesn't
succeed? I guess it doesn't matter much either way since the API can't
propagate errors at this point anyway...

> +static void ps8622_enable(struct drm_bridge *bridge)
> +{
> +	struct ps8622_bridge *ps_bridge = bridge->driver_private;
> +
> +	mutex_lock(&ps_bridge->enable_mutex);
> +	drm_panel_enable(ps_bridge->panel);
> +	mutex_unlock(&ps_bridge->enable_mutex);

What's the enable_mutex protecting here?

> +static void ps8622_disable(struct drm_bridge *bridge)
> +{
> +	struct ps8622_bridge *ps_bridge = bridge->driver_private;
> +
> +	mutex_lock(&ps_bridge->enable_mutex);
> +
> +	if (!ps_bridge->enabled)
> +		goto out;
> +
> +	ps_bridge->enabled = false;
> +
> +	drm_panel_disable(ps_bridge->panel);
> +	msleep(PS8622_PWMO_END_T12_MS);
> +
> +	/*
> +	 * This doesn't matter if the regulators are turned off, but something
> +	 * else might keep them on. In that case, we want to assert the slp gpio
> +	 * to lower power.
> +	 */
> +	gpiod_set_value(ps_bridge->gpio_slp_n, 0);
> +
> +	if (ps_bridge->v12)
> +		regulator_disable(ps_bridge->v12);
> +
> +	/*
> +	 * Sleep for at least the amount of time that it takes the power rail to
> +	 * fall to prevent asserting the rst gpio from doing anything.
> +	 */
> +	usleep_range(PS8622_POWER_FALL_T16_MAX_US,
> +		     2 * PS8622_POWER_FALL_T16_MAX_US);
> +	gpiod_set_value(ps_bridge->gpio_rst_n, 0);

Does this even matter? Why would it be bad if the reset was asserted
before power went away? Isn't the end result that the chip will be off
and reset to an initial state the next time it's power up anyway?

> +static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
> +		bool force)

Alignment here is slightly odd. We usually follow (in DRM and many other
parts of the kernel) the convention of aligning arguments on subsequent
lines with the first argument on the first line.

> +int ps8622_post_encoder_init(struct drm_bridge *bridge)
> +{
> +	struct ps8622_bridge *ps_bridge = bridge->driver_private;
> +	int ret;
> +
> +	/* bridge is attached to encoder.
> +	 * safe to remove it from the bridge_lookup table.
> +	 */
> +	drm_bridge_remove_from_lookup(bridge);

Like I said for the ptn3460 driver, this should not be here.

> +	ret = drm_bridge_init(bridge->drm_dev, bridge);
> +	if (ret) {
> +		DRM_ERROR("Failed to initialize bridge with drm\n");
> +		return ret;
> +	}

And this should probably happen somewhere else to avoid having to do it
for every driver.

> +static const struct of_device_id ps8622_devices[] = {
> +	{
> +		.compatible = "parade,ps8622",
> +		.data	= &ps8622_data,
> +	}, {
> +		.compatible = "parade,ps8625",
> +		.data	= &ps8625_data,
> +	}, {

The above uses a mix of spaces and tabs for padding (tabs between .data
and =). Single spaces will do.

> +		/* end node */

Nit: it's not a node, it's an entry or element.

> +	}
> +};
> +MODULE_DEVICE_TABLE(of, ps8622_devices);
> +
> +static inline struct ps8622_device_data *get_device_data(struct device *dev)
> +{
> +	const struct of_device_id *match =
> +			of_match_device(ps8622_devices, dev);
> +
> +	return (struct ps8622_device_data *)match->data;
> +}

Please drop this. First of all, match->data is void *, so there's no
need for the explicit casting. Second, match->data is also const, so
you're effectively casting that away.

> +
> +static int ps8622_probe(struct i2c_client *client,
> +					const struct i2c_device_id *id)
> +{
> +	struct device *dev = &(client->dev);

No need for the parentheses here.

> +	struct device_node *panel_node, *backlight_node;
> +	struct drm_bridge *bridge;
> +	struct backlight_device *backlight_dev;
> +	struct ps8622_bridge *ps_bridge;

Have you considered naming this simply "ps" to make it shorter? There's
some weird formatting below just because this is a very long variable
name.

> +	const struct ps8622_device_data *device_data;
> +	int ret;

It's just as easy (and shorter) to do this here:

	const struct ps8622_device_data *data;
	const struct of_device_id *match;

	match = of_match_device(ps8622_devices, dev);
	data = match->data;

> +	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
> +	if (!bridge) {
> +		DRM_ERROR("Failed to allocate drm bridge\n");
> +		return -ENOMEM;
> +	}
> +
> +	ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
> +	if (!ps_bridge) {
> +		DRM_ERROR("could not allocate ps bridge\n");
> +		return -ENOMEM;
> +	}
> +
> +	panel_node = of_parse_phandle(dev->of_node, "panel", 0);
> +	if (panel_node) {
> +		ps_bridge->panel = of_drm_find_panel(panel_node);
> +		of_node_put(panel_node);
> +		if (!ps_bridge->panel)
> +			return -EPROBE_DEFER;
> +	}
> +
> +	backlight_dev = NULL;

It's more idiomatic to initialize these when you declare them to avoid
sprinkling them across the code like this.

> +	backlight_node = of_parse_phandle(dev->of_node, "backlight", 0);
> +	if (backlight_node) {
> +		backlight_dev = of_find_backlight_by_node(backlight_node);
> +		of_node_put(backlight_node);
> +		if (!backlight_dev)
> +			return -EPROBE_DEFER;

It seems like in this case you aren't storing the backlight anywhere. Is
there a reason for that? Is it because the same backlight is used by the
panel driver and it does the controlling from there? If so it might be
better to use a boolean property here rather than a phandle to another
backlight device. Using a phandle usually signal that you do want to use
the device in some way.

> +	}
> +
> +	mutex_init(&ps_bridge->enable_mutex);
> +
> +	bridge->dev = dev;
> +	bridge->driver_private = ps_bridge;
> +	bridge->funcs = &ps8622_bridge_funcs;
> +
> +	ps_bridge->client = client;
> +	ps_bridge->bridge = bridge;
> +
> +	device_data = get_device_data(dev);
> +
> +	ps_bridge->v12 = devm_regulator_get(&client->dev, "vdd_bridge");

vdd_bridge is not a valid name for a regulator. This will translate to
vdd_bridge-supply for a DT property and you shouldn't be using
underscores for them. Also this property isn't documented in the
binding.

> +	if (IS_ERR(ps_bridge->v12)) {
> +		DRM_INFO("no 1.2v regulator found for PS8622\n");
> +		ps_bridge->v12 = NULL;
> +	}

Does this ever happen? As far as I know the regulator core will give you
a dummy regulator when booting using DT, so errors returned here will
always be real errors that you likely won't want to ignore.

> +
> +	ps_bridge->gpio_slp_n = devm_gpiod_get(&client->dev, "sleep");
> +	if (IS_ERR(ps_bridge->gpio_slp_n)) {
> +		ret = PTR_ERR(ps_bridge->gpio_slp_n);
> +		DRM_ERROR("cannot get gpio_slp_n %d\n", ret);
> +		goto err_client;
> +	} else {
> +		ret = gpiod_direction_output(ps_bridge->gpio_slp_n, 1);
> +		if (ret) {
> +			DRM_ERROR("cannot configure gpio_slp_n\n");
> +			goto err_client;
> +		}
> +	}
> +
> +	ps_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset");
> +	if (IS_ERR(ps_bridge->gpio_rst_n)) {
> +		ret = PTR_ERR(ps_bridge->gpio_rst_n);
> +		DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
> +		goto err_client;
> +	} else {
> +		/*
> +		 * Assert the reset pin high to avoid the bridge being
> +		 * initialized prematurely
> +		 */
> +		ret = gpiod_direction_output(ps_bridge->gpio_rst_n, 1);
> +		if (ret) {
> +			DRM_ERROR("cannot configure gpio_slp_n\n");
> +			goto err_client;
> +		}
> +	}

Just as a side-note, there's an API under discussion that will allow
gpio_desc's to be configured at the same time as they are requested.
This driver should probably convert to that API.

> +	ps_bridge->max_lane_count = device_data->max_lane_count;
> +
> +	if (of_property_read_u8(dev->of_node, "lane-count",
> +						&ps_bridge->lane_count))
> +		ps_bridge->lane_count = ps_bridge->max_lane_count;
> +	else if (ps_bridge->lane_count > ps_bridge->max_lane_count) {
> +		DRM_INFO("lane-count property is too high for DP bridge\n");
> +		ps_bridge->lane_count = ps_bridge->max_lane_count;
> +	}

Perhaps this should clarify that you're falling back to max_lane_count.

> +
> +	if (!backlight_dev) {
> +		ps_bridge->bl = backlight_device_register("ps8622-backlight",
> +				dev, ps_bridge, &ps8622_backlight_ops,
> +				NULL);
> +		if (IS_ERR(ps_bridge->bl)) {
> +			DRM_ERROR("failed to register backlight\n");
> +			ret = PTR_ERR(ps_bridge->bl);
> +			ps_bridge->bl = NULL;

No need to set this to NULL since you'll return with an error and
ps_bridge will be freed.

> +			goto err_client;
> +		}
> +		ps_bridge->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
> +		ps_bridge->bl->props.brightness = PS8622_MAX_BRIGHTNESS;

Perhaps you want to initialize bl->props.power to FB_BLANK_POWERDOWN at
this point. The reason is that if you don't then the backlight will be
on by default (FB_BLANK_UNBLANK == 0). Many backlight drivers do call
backlight_update_status() after registering with the core to set the
initial state. It looks like you're not doing that here, but it might be
better to still set this to reflect what the initial state should be.

I'm assuming you want it disabled to avoid visual glitches when you turn
on the display. Of course if the bootloader already turned it on and
initialized the display, then you'll get flickering... but I guess
that's a problem to solve another day.

> +	}
> +
> +	i2c_set_clientdata(client, ps_bridge);
> +
> +	drm_bridge_add_for_lookup(bridge);
> +
> +	return 0;
> +
> +err_client:
> +	DRM_ERROR("device probe failed : %d\n", ret);

No need for this. The driver core typically tells you already.

> +static int ps8622_remove(struct i2c_client *client)
> +{
> +	struct ps8622_bridge *ps_bridge = i2c_get_clientdata(client);
> +
> +	if (ps_bridge->bl)
> +		backlight_device_unregister(ps_bridge->bl);
> +
> +	return 0;
> +}

You'll also want to call drm_bridge_remove() here.

> +static const struct i2c_device_id ps8622_i2c_table[] = {
> +	{"parade", 0},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);

This table doesn't look right. Shouldn't that be:

	{ "ps8622", 0 },
	{ "ps8625", 0 },

? And perhaps use the .driver_data field to refer to the device data
like for the of_device_id table?

> +struct i2c_driver ps8622_driver = {
> +	.id_table	= ps8622_i2c_table,
> +	.probe		= ps8622_probe,
> +	.remove		= ps8622_remove,
> +	.driver		= {
> +		.name	= "parade",

That's an awfully generic name. I'd suggest "ps8622".

> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(ps8622_devices),

As for ptn3460, this has a hard dependency on OF, so of_match_ptr()
isn't useful.

> +	},
> +};
> +module_i2c_driver(ps8622_driver);
> +
> +MODULE_AUTHOR("Vincent Palatin <vpalatin@xxxxxxxxxxxx>");
> +MODULE_DESCRIPTION("Parade ps8622 eDP-LVDS converter driver");
> +MODULE_LICENSE("GPL");

"GPL v2"

Thierry

Attachment: pgpOGmd01l8sF.pgp
Description: PGP signature


[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  Powered by Linux