Загрузка данных
static const struct drm_bridge_funcs adv7511_bridge_funcs = {
.enable = adv7511_bridge_enable,
.disable = adv7511_bridge_disable,
.get_modes = adv7511_bridge_get_modes,
.mode_set = adv7511_bridge_mode_set,
.mode_valid = adv7511_bridge_mode_valid,
.attach = adv7511_bridge_attach,
.detect = adv7511_bridge_detect,
.edid_read = adv7511_bridge_edid_read,
.hpd_notify = adv7511_bridge_hpd_notify,
.detach = adv7511_bridge_detach,
};
static int adv7511_probe(struct i2c_client *i2c)
{
struct adv7511_link_config link_config;
struct adv7511 *adv7511;
struct device *dev = &i2c->dev;
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
struct device_node *remote_node = NULL, *endpoint = NULL;
struct of_changeset ocs;
#endif
unsigned int main_i2c_addr = i2c->addr << 1;
unsigned int edid_i2c_addr = main_i2c_addr + 4;
unsigned int cec_i2c_addr = main_i2c_addr - 2;
unsigned int pkt_i2c_addr = main_i2c_addr - 0xa;
unsigned int val;
int ret;
if (!dev->of_node)
return -EINVAL;
adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
if (!adv7511)
return -ENOMEM;
adv7511->i2c_main = i2c;
adv7511->powered = false;
adv7511->status = connector_status_disconnected;
adv7511->info = i2c_get_match_data(i2c);
memset(&link_config, 0, sizeof(link_config));
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL, &adv7511->next_bridge);
if (ret && ret != -ENODEV)
return ret;
if (adv7511->info->link_config)
ret = adv7511_parse_dt(dev->of_node, &link_config);
else
ret = adv7533_parse_dt(dev->of_node, adv7511);
if (ret)
return ret;
ret = adv7511_init_regulators(adv7511);
if (ret) {
dev_err_probe(dev, ret, "failed to init regulators\n");
goto err_of_node_put;
}
if (adv7511->addr_cec != 0)
cec_i2c_addr = adv7511->addr_cec << 1;
else
adv7511->addr_cec = cec_i2c_addr >> 1;
if (adv7511->addr_edid != 0)
edid_i2c_addr = adv7511->addr_edid << 1;
else
adv7511->addr_edid = edid_i2c_addr >> 1;
if (adv7511->addr_pkt != 0)
pkt_i2c_addr = adv7511->addr_pkt << 1;
else
adv7511->addr_pkt = pkt_i2c_addr >> 1;
/*
* The power down GPIO is optional. If present, toggle it from active to
* inactive to wake up the encoder.
*/
adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
if (IS_ERR(adv7511->gpio_pd)) {
ret = PTR_ERR(adv7511->gpio_pd);
goto uninit_regulators;
}
if (adv7511->gpio_pd) {
usleep_range(5000, 6000);
gpiod_set_value_cansleep(adv7511->gpio_pd, 0);
}
adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
if (IS_ERR(adv7511->regmap)) {
ret = PTR_ERR(adv7511->regmap);
goto uninit_regulators;
}
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
if (ret)
goto uninit_regulators;
dev_dbg(dev, "Rev. %d\n", val);
if (adv7511->info->type == ADV7511)
ret = regmap_register_patch(adv7511->regmap,adv7511_fixed_registers, ARRAY_SIZE(adv7511_fixed_registers));
else
ret = adv7533_patch_registers(adv7511);
if (ret)
goto uninit_regulators;
adv7511_packet_disable(adv7511, 0xffff);
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,edid_i2c_addr);
adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",adv7511->addr_edid);
if (IS_ERR(adv7511->i2c_edid)) {
ret = PTR_ERR(adv7511->i2c_edid);
goto uninit_regulators;
}
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
pkt_i2c_addr);
adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet",adv7511->addr_pkt);
if (IS_ERR(adv7511->i2c_packet)) {
ret = PTR_ERR(adv7511->i2c_packet);
goto err_i2c_unregister_edid;
}
regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
cec_i2c_addr);
ret = adv7511_init_cec_regmap(adv7511);
if (ret)
goto err_i2c_unregister_packet;
INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
adv7511_power_off(adv7511);
i2c_set_clientdata(i2c, adv7511);
if (adv7511->info->link_config)
adv7511_set_link_config(adv7511, &link_config);
ret = adv7511_cec_init(dev, adv7511);
if (ret)
goto err_unregister_cec;
adv7511->bridge.funcs = &adv7511_bridge_funcs;
adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
if (adv7511->i2c_main->irq)
adv7511->bridge.ops |= DRM_BRIDGE_OP_HPD;
adv7511->bridge.of_node = dev->of_node;
adv7511->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
drm_bridge_add(&adv7511->bridge);
adv7511_audio_init(dev, adv7511);
if (i2c->irq) {
init_waitqueue_head(&adv7511->wq);
ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
adv7511_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(dev),
adv7511);
if (ret)
goto err_unregister_cec;
}
return 0;
err_unregister_cec:
cec_unregister_adapter(adv7511->cec_adap);
i2c_unregister_device(adv7511->i2c_cec);
clk_disable_unprepare(adv7511->cec_clk);
err_i2c_unregister_packet:
i2c_unregister_device(adv7511->i2c_packet);
err_i2c_unregister_edid:
i2c_unregister_device(adv7511->i2c_edid);
uninit_regulators:
adv7511_uninit_regulators(adv7511);
err_of_node_put:
of_node_put(adv7511->host_node);
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
if (ret == -EPROBE_DEFER)
return ret;
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
if (endpoint) {
remote_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
}
if (!remote_node)
return ret;
/* Find remote's endpoint connected to us and detach it */
endpoint = NULL;
while ((endpoint = of_graph_get_next_endpoint(remote_node,endpoint))) {
struct device_node *us;
us = of_graph_get_remote_port_parent(endpoint);
if (us == dev->of_node)
break;
}
of_node_put(remote_node);
if (!endpoint)
return ret;
of_changeset_init(&ocs);
of_changeset_detach_node(&ocs, endpoint);
ret = of_changeset_apply(&ocs);
if (!ret)
dev_warn(dev,
"Probe failed. Remote port '%s' disabled\n",
remote_node->full_name);
#endif
return ret;
}
static void adv7511_remove(struct i2c_client *i2c)
{
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
of_node_put(adv7511->host_node);
adv7511_uninit_regulators(adv7511);
drm_bridge_remove(&adv7511->bridge);
adv7511_audio_exit(adv7511);
cec_unregister_adapter(adv7511->cec_adap);
i2c_unregister_device(adv7511->i2c_cec);
clk_disable_unprepare(adv7511->cec_clk);
i2c_unregister_device(adv7511->i2c_packet);
i2c_unregister_device(adv7511->i2c_edid);
}
static const struct adv7511_chip_info adv7511_chip_info = {
.type = ADV7511,
.supply_names = adv7511_supply_names,
.num_supplies = ARRAY_SIZE(adv7511_supply_names),
.link_config = true,
};
static const struct adv7511_chip_info adv7533_chip_info = {
.type = ADV7533,
.max_mode_clock_khz = 80000,
.max_lane_freq_khz = 800000,
.supply_names = adv7533_supply_names,
.num_supplies = ARRAY_SIZE(adv7533_supply_names),
.reg_cec_offset = ADV7533_REG_CEC_OFFSET,
.has_dsi = true,
};
static const struct adv7511_chip_info adv7535_chip_info = {
.type = ADV7535,
.max_mode_clock_khz = 148500,
.max_lane_freq_khz = 891000,
.supply_names = adv7533_supply_names,
.num_supplies = ARRAY_SIZE(adv7533_supply_names),
.reg_cec_offset = ADV7533_REG_CEC_OFFSET,
.has_dsi = true,
.hpd_override_enable = true,
};
static const struct i2c_device_id adv7511_i2c_ids[] = {
{ "adv7511", (kernel_ulong_t)&adv7511_chip_info },
{ "adv7511w", (kernel_ulong_t)&adv7511_chip_info },
{ "adv7513", (kernel_ulong_t)&adv7511_chip_info },
{ "adv7533", (kernel_ulong_t)&adv7533_chip_info },
{ "adv7535", (kernel_ulong_t)&adv7535_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
static const struct of_device_id adv7511_of_ids[] = {
{ .compatible = "adi,adv7511", .data = &adv7511_chip_info },
{ .compatible = "adi,adv7511w", .data = &adv7511_chip_info },
{ .compatible = "adi,adv7513", .data = &adv7511_chip_info },
{ .compatible = "adi,adv7533", .data = &adv7533_chip_info },
{ .compatible = "adi,adv7535", .data = &adv7535_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, adv7511_of_ids);
static struct mipi_dsi_driver adv7533_dsi_driver = {
.driver.name = "adv7533",
};
static struct i2c_driver adv7511_driver = {
.driver = {
.name = "adv7511",
.of_match_table = adv7511_of_ids,
},
.id_table = adv7511_i2c_ids,
.probe = adv7511_probe,
.remove = adv7511_remove,
};
static int __init adv7511_init(void)
{
int ret;
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
ret = mipi_dsi_driver_register(&adv7533_dsi_driver);
if (ret)
return ret;
}
ret = i2c_add_driver(&adv7511_driver);
if (ret) {
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
mipi_dsi_driver_unregister(&adv7533_dsi_driver);
}
return ret;
}
module_init(adv7511_init);
static void __exit adv7511_exit(void)
{
i2c_del_driver(&adv7511_driver);
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
mipi_dsi_driver_unregister(&adv7533_dsi_driver);
}
module_exit(adv7511_exit);
весь код не выслылаю, он большой, только то, что необходимо. Если нужны реализации конкретных функций, напиши