On Thu, 30 Jan 2014 14:20:56 +0200
Jyri Sarha <jsarha at ti.com> wrote:

> I am having trouble getting the tda998x-codec working on BBB. The 
> problem is I do not have a DT node for the tda998x driver. Instead I 
> have tilcdc-slave node that provides pdata for the tda-driver.
> 
> I am thinking of solving the problem by adding a reference to the 
> i2c-adapter hosting tda998x as an optional DT property to the codec 
> node. I could then dig the driver instance from the i2c adapter's 
> children. Any better ideas?

I better think about a 'normal' DT definition:

- in the DT, define the tda998x in a i2c subnode:

  &i2c0 {
        tda998x: hdmi-encoder {
                compatible = "nxp,tda998x";
                reg = <0x70>;
                /* the video ports are OK by default */
                /* define the interrupt if you want to use it */
        };
  };

- in tilcdc_slave.c, in the function slave_encoder_create(), instead of
  using drm_i2c_encoder_init(), do quite the same, but without calling
  request_module() nor i2c_new_device().

  This can be done as follows (the code is not compiled):

--------------------8<---------------------
static struct drm_encoder *slave_encoder_create(struct drm_device *dev,
                struct slave_module *mod)
{
        struct slave_encoder *slave_encoder;
        struct drm_encoder *encoder;
        int ret;
/* ------ added ------ */
        struct device_node *np;
        static const struct of_device_id tda_dt[] = {
                { .compatible = "nxp,tda998x" },
                { },
        };
/* ------ end added ------ */

        ... no change ...

         drm_encoder_helper_add(encoder, &slave_encoder_helper_funcs);

/* ------ added ------ */

        /* search the tda998x device */
        np = of_find_matching_node_and_match(NULL, tda_dt, NULL);
        if (np && of_device_is_available(np)) {
                struct i2c_client *i2c_client;
                struct drm_i2c_encoder_driver *encoder_drv;
                struct module *module;

                                        /* the tda998x is in the DT */

                i2c_client = of_find_i2c_device_by_node(np);
                of_node_put(np);
                if (!i2c_client) {
                        dev_err(dev->dev, "no tda998x i2c client\n");
                        goto fail;
                }

                to_encoder_slave(encoder)->bus_priv = i2c_client;

                encoder_drv = to_drm_i2c_encoder_driver(
                                to_i2c_driver(i2c_client->dev.driver));

                /* lock the tda998x module in memory */
                module = to_i2c_driver(i2c_client->dev.driver)->driver.owner;
                if (!module || !try_module_get(module)) {
                        dev_err(dev->dev, "cannot get module %s\n", 
module->name);
                        goto fail;
                }

                ret = encoder_drv->encoder_init(i2c_client, dev, encoder_slave);
                if (ret < 0) {
                        dev_err(dev->dev, "slave encoder init failed\n");
                        module_put(module);
                        goto fail;
                }
                                        /* set_config is useless */
                return encoder;
        }

/* ------ end added ------ */

        ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), mod->i2c, 
&info);
        if (ret)
                goto fail;

        return encoder;

fail:
        slave_encoder_destroy(encoder);
        return NULL;
}
--------------------8<---------------------

When the tda998x is in the DT, the i2c_client is already created.
It must not be freed, and so, the function drm_i2c_encoder_destroy()
must not be called. But, the module must be explicitly unlocked in
slave_encoder_destroy(), and then, there must be some flag in the
structures for this job to be done...

-- 
Ken ar c'henta? |             ** Breizh ha Linux atav! **
Jef             |               http://moinejf.free.fr/

Reply via email to