mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
drm/i2c: adv7511: Convert to drm_bridge
We don't want to use the old i2c slave encoder interface anymore. Remove that and make the i2c driver create a drm_bridge entity instead. Converting to bridges helps because the kms drivers don't need to exract encoder slave ops from this driver and use it within their own encoder/connector ops. The driver now creates its own connector when a kms driver attaches itself to the bridge. Therefore, kms drivers don't need to create their own connectors anymore. The old encoder slave ops are now used by the new bridge and connector entities. The of_node member in drm_bridge is accessible only when CONFIG_OF is enabled. The driver anyway only works only when OF is available. Make the driver depend on OF in its Kconfig. Signed-off-by: Archit Taneja <architt@codeaurora.org>
This commit is contained in:
parent
2ae9958878
commit
e12c2f6455
2 changed files with 140 additions and 74 deletions
|
@ -3,6 +3,7 @@ menu "I2C encoder or helper chips"
|
|||
|
||||
config DRM_I2C_ADV7511
|
||||
tristate "AV7511 encoder"
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
|
||||
#include "adv7511.h"
|
||||
|
||||
|
@ -36,7 +37,8 @@ struct adv7511 {
|
|||
bool edid_read;
|
||||
|
||||
wait_queue_head_t wq;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector connector;
|
||||
|
||||
bool embedded_sync;
|
||||
enum adv7511_sync_polarity vsync_polarity;
|
||||
|
@ -48,11 +50,6 @@ struct adv7511 {
|
|||
struct gpio_desc *gpio_pd;
|
||||
};
|
||||
|
||||
static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
|
||||
{
|
||||
return to_encoder_slave(encoder)->slave_priv;
|
||||
}
|
||||
|
||||
/* ADI recommended values for proper operation. */
|
||||
static const struct reg_sequence adv7511_fixed_registers[] = {
|
||||
{ 0x98, 0x03 },
|
||||
|
@ -446,8 +443,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
|
|||
regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
|
||||
|
||||
if (irq0 & ADV7511_INT0_HPD && adv7511->encoder)
|
||||
drm_helper_hpd_irq_event(adv7511->encoder->dev);
|
||||
if (irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
|
||||
drm_helper_hpd_irq_event(adv7511->connector.dev);
|
||||
|
||||
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
|
||||
adv7511->edid_read = true;
|
||||
|
@ -563,13 +560,12 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
|
|||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Encoder operations
|
||||
* ADV75xx helpers
|
||||
*/
|
||||
|
||||
static int adv7511_get_modes(struct drm_encoder *encoder,
|
||||
static int adv7511_get_modes(struct adv7511 *adv7511,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
|
||||
struct edid *edid;
|
||||
unsigned int count;
|
||||
|
||||
|
@ -606,21 +602,9 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
|
|||
return count;
|
||||
}
|
||||
|
||||
static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
|
||||
|
||||
if (mode == DRM_MODE_DPMS_ON)
|
||||
adv7511_power_on(adv7511);
|
||||
else
|
||||
adv7511_power_off(adv7511);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
adv7511_encoder_detect(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector)
|
||||
adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
|
||||
{
|
||||
struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
|
||||
enum drm_connector_status status;
|
||||
unsigned int val;
|
||||
bool hpd;
|
||||
|
@ -644,7 +628,7 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
|
|||
if (status == connector_status_connected && hpd && adv7511->powered) {
|
||||
regcache_mark_dirty(adv7511->regmap);
|
||||
adv7511_power_on(adv7511);
|
||||
adv7511_get_modes(encoder, connector);
|
||||
adv7511_get_modes(adv7511, connector);
|
||||
if (adv7511->status == connector_status_connected)
|
||||
status = connector_status_disconnected;
|
||||
} else {
|
||||
|
@ -658,8 +642,8 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
|
|||
return status;
|
||||
}
|
||||
|
||||
static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
static int adv7511_mode_valid(struct adv7511 *adv7511,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 165000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
@ -667,11 +651,10 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
static void adv7511_mode_set(struct adv7511 *adv7511,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
|
||||
unsigned int low_refresh_rate;
|
||||
unsigned int hsync_polarity = 0;
|
||||
unsigned int vsync_polarity = 0;
|
||||
|
@ -762,12 +745,111 @@ static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
|
|||
adv7511->f_tmds = mode->clock;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
|
||||
.dpms = adv7511_encoder_dpms,
|
||||
.mode_valid = adv7511_encoder_mode_valid,
|
||||
.mode_set = adv7511_encoder_mode_set,
|
||||
.detect = adv7511_encoder_detect,
|
||||
.get_modes = adv7511_get_modes,
|
||||
/* Connector funcs */
|
||||
static struct adv7511 *connector_to_adv7511(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct adv7511, connector);
|
||||
}
|
||||
|
||||
static int adv7511_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct adv7511 *adv = connector_to_adv7511(connector);
|
||||
|
||||
return adv7511_get_modes(adv, connector);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
adv7511_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct adv7511 *adv = connector_to_adv7511(connector);
|
||||
|
||||
return adv7511_mode_valid(adv, mode);
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs adv7511_connector_helper_funcs = {
|
||||
.get_modes = adv7511_connector_get_modes,
|
||||
.mode_valid = adv7511_connector_mode_valid,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
adv7511_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct adv7511 *adv = connector_to_adv7511(connector);
|
||||
|
||||
return adv7511_detect(adv, connector);
|
||||
}
|
||||
|
||||
static struct drm_connector_funcs adv7511_connector_funcs = {
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = adv7511_connector_detect,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
/* Bridge funcs */
|
||||
static struct adv7511 *bridge_to_adv7511(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct adv7511, bridge);
|
||||
}
|
||||
|
||||
static void adv7511_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct adv7511 *adv = bridge_to_adv7511(bridge);
|
||||
|
||||
adv7511_power_on(adv);
|
||||
}
|
||||
|
||||
static void adv7511_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct adv7511 *adv = bridge_to_adv7511(bridge);
|
||||
|
||||
adv7511_power_off(adv);
|
||||
}
|
||||
|
||||
static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
struct adv7511 *adv = bridge_to_adv7511(bridge);
|
||||
|
||||
adv7511_mode_set(adv, mode, adj_mode);
|
||||
}
|
||||
|
||||
static int adv7511_bridge_attach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct adv7511 *adv = bridge_to_adv7511(bridge);
|
||||
int ret;
|
||||
|
||||
if (!bridge->encoder) {
|
||||
DRM_ERROR("Parent encoder object not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
adv->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
ret = drm_connector_init(bridge->dev, &adv->connector,
|
||||
&adv7511_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize connector with drm\n");
|
||||
return ret;
|
||||
}
|
||||
drm_connector_helper_add(&adv->connector,
|
||||
&adv7511_connector_helper_funcs);
|
||||
drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct drm_bridge_funcs adv7511_bridge_funcs = {
|
||||
.enable = adv7511_bridge_enable,
|
||||
.disable = adv7511_bridge_disable,
|
||||
.mode_set = adv7511_bridge_mode_set,
|
||||
.attach = adv7511_bridge_attach,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -944,6 +1026,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
|||
|
||||
adv7511_set_link_config(adv7511, &link_config);
|
||||
|
||||
adv7511->bridge.funcs = &adv7511_bridge_funcs;
|
||||
adv7511->bridge.of_node = dev->of_node;
|
||||
|
||||
ret = drm_bridge_add(&adv7511->bridge);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add adv7511 bridge\n");
|
||||
goto err_i2c_unregister_device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_i2c_unregister_device:
|
||||
|
@ -956,6 +1047,8 @@ static int adv7511_remove(struct i2c_client *i2c)
|
|||
{
|
||||
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
|
||||
|
||||
drm_bridge_remove(&adv7511->bridge);
|
||||
|
||||
i2c_unregister_device(adv7511->i2c_edid);
|
||||
|
||||
kfree(adv7511->edid);
|
||||
|
@ -963,20 +1056,6 @@ static int adv7511_remove(struct i2c_client *i2c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
|
||||
struct drm_encoder_slave *encoder)
|
||||
{
|
||||
|
||||
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
|
||||
|
||||
encoder->slave_priv = adv7511;
|
||||
encoder->slave_funcs = &adv7511_encoder_funcs;
|
||||
|
||||
adv7511->encoder = &encoder->base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adv7511_i2c_ids[] = {
|
||||
{ "adv7511", 0 },
|
||||
{ "adv7511w", 0 },
|
||||
|
@ -993,31 +1072,17 @@ static const struct of_device_id adv7511_of_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, adv7511_of_ids);
|
||||
|
||||
static struct drm_i2c_encoder_driver adv7511_driver = {
|
||||
.i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adv7511",
|
||||
.of_match_table = adv7511_of_ids,
|
||||
},
|
||||
.id_table = adv7511_i2c_ids,
|
||||
.probe = adv7511_probe,
|
||||
.remove = adv7511_remove,
|
||||
static struct i2c_driver adv7511_driver = {
|
||||
.driver = {
|
||||
.name = "adv7511",
|
||||
.of_match_table = adv7511_of_ids,
|
||||
},
|
||||
|
||||
.encoder_init = adv7511_encoder_init,
|
||||
.id_table = adv7511_i2c_ids,
|
||||
.probe = adv7511_probe,
|
||||
.remove = adv7511_remove,
|
||||
};
|
||||
|
||||
static int __init adv7511_init(void)
|
||||
{
|
||||
return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver);
|
||||
}
|
||||
module_init(adv7511_init);
|
||||
|
||||
static void __exit adv7511_exit(void)
|
||||
{
|
||||
drm_i2c_encoder_unregister(&adv7511_driver);
|
||||
}
|
||||
module_exit(adv7511_exit);
|
||||
module_i2c_driver(adv7511_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
|
||||
|
|
Loading…
Reference in a new issue