This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DM8168: EIO when adding an I2C regulator

Other Parts Discussed in Thread: TPS53819A, PCF8575

Hi, 

I get a EIO which is thrown inside tps53819a_probe when trying to register a i2c regulator. It seems like the exception is because of lacking platform_data.

Basically what I did is casting the default gpio-regulator registration into the i2c regulator's, and add some driver support for the i2c regulator.

1. Add regulator specific data to the board file at "arch/arm/mach-omap2/board-dm8168z3.c":

#elif CONFIG_REGULATOR_TPS53819A
static struct regulator_consumer_supply ti816x_tps53819a_dcdc_supply[] = {
	{
		.supply = "tps53819a",
	},
};

static struct regulator_init_data tps53819a_pmic_init_data = {
	.constraints = {
		.min_uV		= 800000,
		.max_uV		= 1500000,
		.valid_ops_mask	= (REGULATOR_CHANGE_VOLTAGE |
			REGULATOR_CHANGE_STATUS),
	},
	.num_consumer_supplies	= ARRAY_SIZE(ti816x_tps53819a_dcdc_supply),
	.consumer_supplies	= ti816x_tps53819a_dcdc_supply,
};

/* TPS regulator platform data */
static struct tps53819a_reg_platform_data tps53819a_vr_init_data = {
	.name			= "tps53819a",
	.pmic_init_data		= &tps53819a_pmic_init_data,
};

/* VCORE for SR regulator init */
static struct platform_device ti816x_tps53819a_vr_device = {
	.name	= "tps53819a",
	.id		= -1,
	.dev    = {
		      .platform_data = &tps53819a_vr_init_data,
	},
};

static void __init ti816x_tps53819a_vr_init(void)
{
	if (platform_device_register(&ti816x_tps53819a_vr_device))
		printk(KERN_ERR "failed to register ti816x_tps53819a_vr device\n");
        else
		printk(KERN_INFO "registered ti816x_tps53819a_vr device\n");
}
.... 
static struct i2c_board_info __initdata z3dm816x_i2c_boardinfo1[] = {
        {
                I2C_BOARD_INFO("tps53819a", 0x2a),
                .platform_data = &tps53819a_vr_init_data,
        },
};
...
#ifdef CONFIG_REGULATOR_TPS53819A
        ti816x_tps53819a_vr_init();

2. Add SR platform specific data based on the chosen PMIC to the devices file at "arch/arm/mach-omap2/devices.c":

static struct ti816x_sr_platform_data ti816x_sr_pdata = {
	.vd_name		= "tps53819a",
	.ip_type		= 2,
	.irq_delay		= 2000,
	.no_of_vds		= 1,
	.no_of_sens		= ARRAY_SIZE(sr_sensor_data),
        .vstep_size_uv          = 49000,
	.enable_on_init		= true,
	.sr_sdata		= sr_sensor_data,
};

3. Add regulator driver support at "kernel/driver/regulator/tps53819a-regulator.c":

static int __devinit tps53819a_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    const struct tps_info *info = (void *)id->driver_data;
    struct regulator_init_data *init_data;
    struct regulator_dev *rdev;
    struct tps_pmic *tps;
    int error;

    if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
        dev_err(&client->dev, "i2c_check_functionality failed!\n");
        return -EIO;
    }

    init_data = client->dev.platform_data;
    if (!init_data) {
        dev_err(&client->dev, "platform_data is null!\n");
    	return -EIO;
    }

    tps = kzalloc(sizeof(*tps), GFP_KERNEL);
    if (!tps)
    	return -ENOMEM;

    mutex_init(&tps->io_lock);

    /* common for all regulators */
    tps->client = client;
    tps->info = info;
    tps->desc.name = info->name;
    tps->desc.n_voltages = ARRAY_SIZE(VDCDC_VSEL_table);
    tps->desc.ops = &tps53819a_dcdc_ops;
    tps->desc.type = REGULATOR_VOLTAGE;
    tps->desc.owner = THIS_MODULE;

    /* Register the Regulator */
    rdev = regulator_register(&tps->desc, &client->dev, init_data, tps);
    if (IS_ERR(rdev)) {
        dev_err(&client->dev, "failed to register %s\n", id->name);
        error = PTR_ERR(rdev);
        goto exit_devreg;
    }

    /* Save regulator for cleanup */
    tps->rdev = rdev;

    i2c_set_clientdata(client, tps);

    return 0;

exit_devreg:
    regulator_unregister(tps->rdev);

    kfree(tps);
    return error;
}

static const struct tps_info tps53819a_regs[] = {
    {
        .name = "TPS53819A_VDCDC",
        .min_uV = TPS53819A_MIN_VOLTAGE,
        .max_uV = TPS53819A_MAX_VOLTAGE,
        .table_len = ARRAY_SIZE(VDCDC_VSEL_table),
        .table = VDCDC_VSEL_table,
    },
};

static const struct i2c_device_id tps53819a_id[] = {
    {
        .name = "tps53819a",
        .driver_data = (unsigned long) tps53819a_regs,
    },
};

MODULE_DEVICE_TABLE(i2c, tps53819a_id);

static struct i2c_driver tps53819a_i2c_driver = {
    .driver = {
        .name = "tps53819a",
        .owner = THIS_MODULE,
    },
    .probe = tps53819a_probe,
    .remove = __devexit_p(tps53819a_remove),
    .id_table = tps53819a_id,
};

static int __init tps53819a_init(void)
{
    printk(KERN_INFO "regulator: %s\n", __func__);
    return i2c_add_driver(&tps53819a_i2c_driver);
}
module_init(tps53819a_init);

Thanks,

Guang

  • Hi Guang,

    Are you using EZSDK or DVR RDK or else?

    Guang Yang40 said:
    "arch/arm/mach-omap2/board-dm8168z3.c":

    Are you using DM8168 Z3 board?

    Please see if the below wiki pages will be in help:

    You can also ask/check in our PMIC forum:

    Regards,
    Pavel

  • Hi Pavel,

    What we are using right now is not Z3 board. We develop a new board with dm8168 and tps53819a embedded, and they should communicate via i2c bus. The SDK is RidgeRun’s.

    All wiki pages are vaguely saying "arch/arm/mach-omap2/board-ti8168z3.c file needs to be modfied with additional defintions", I'm wondering if more input can be put on my issue.

    static struct i2c_board_info __initdata z3dm816x_i2c_boardinfo1[] = {
            {
                    I2C_BOARD_INFO("tps53819a", 0x2a),
                    .platform_data = &tps53819a_vr_init_data,
            },
    }

    Above code can pass the name and addr to the i2c_client properly, but adding .platform_data here will make kernel bootup get stuck.


    Thanks,
    Guang

  • Guang,

    Guang Yang40 said:
    What we are using right now is not Z3 board. We develop a new board with dm8168 and tps53819a embedded, and they should communicate via i2c bus.

    So you are using DM8168 based custom board.

    Guang Yang40 said:
    The SDK is RidgeRun’s.

    I am not familiar with this SDK. You might need contact RidgeRun to check if they have something to share.

    Guang Yang40 said:
    All wiki pages are vaguely saying "arch/arm/mach-omap2/board-ti8168z3.c file

    Are you sure this is the correct file? On my side the file is "arch/arm/mach-omap2/board-ti8168evm.c"

    Guang Yang40 said:
    static struct i2c_board_info __initdata z3dm816x_i2c_boardinfo1[] = { { I2C_BOARD_INFO("tps53819a", 0x2a), .platform_data = &tps53819a_vr_init_data, }, }

    In arch/arm/mach-omap2/board-ti8168evm.c I have:

    static struct i2c_board_info __initdata ti816x_i2c_boardinfo0[] = {
        {
            I2C_BOARD_INFO("eeprom", 0x50),
            .platform_data    = &eeprom_info,
        },
        {
            I2C_BOARD_INFO("cpld", 0x23),
        },
        {
            I2C_BOARD_INFO("tlv320aic3x", 0x18),
        },
        {
            I2C_BOARD_INFO("IO Expander", 0x20),
        },

    };

    static struct i2c_board_info __initdata ti816x_i2c_boardinfo1[] = {
        {
            I2C_BOARD_INFO("pcf8575_1", 0x20),
        },
        {
            I2C_BOARD_INFO("sii9022a", 0x39),
            .platform_data    = &sii9022a_pdata,
        },
        {
            I2C_BOARD_INFO("pcf8575_1", 0x21),
        },
        {
            I2C_BOARD_INFO("pcf8575_1", 0x2e),
        },
    };

    static struct at24_platform_data eeprom_info = {
        .byte_len       = (256*1024) / 8,
        .page_size      = 64,
        .flags          = AT24_FLAG_ADDR16,
    };

    static struct sii9022a_platform_data sii9022a_pdata = {
        .hdmi_hot_plug_gpio_intr_line   = 0,
        .sync_mode                      = 0,
        .clk_edge                       = 0,
    };

    Are you sure you have your PMIC attached to I2C1 at address 0x2A? How does your PMIC platform data structure looks like? Below is what we have regarding the PMIC in DM816x EVM;

    /* GPIO regulator platform data */
    static struct gpio_reg_platform_data gpio_vr_init_data = {
        .name            = "VFB",
        .pmic_init_data        = &gpio_pmic_init_data,
        .gpio_vsel_table    = ti816x_vsel_table,
        .num_voltages        = ARRAY_SIZE(ti816x_vsel_table),
        .gpios            = vcore_gpios,
        .gpio_single_bank    = true,
        .gpio_arr_mask        = 0xF,
        .num_gpio_pins        = ARRAY_SIZE(vcore_gpios),
        .pmic_vout        = 600000,
    };

    /* VCORE for SR regulator init */
    static struct platform_device ti816x_gpio_vr_device = {
        .name        = "gpio_vr",
        .id        = -1,
        .dev = {
            .platform_data = &gpio_vr_init_data,
        },
    };

    Regards,
    Pavel