xref: /openbmc/linux/drivers/mfd/tps6507x.c (revision dc0c386e)
131dd6a26STodd Fischer /*
231dd6a26STodd Fischer  * tps6507x.c  --  TPS6507x chip family multi-function driver
331dd6a26STodd Fischer  *
431dd6a26STodd Fischer  *  Copyright (c) 2010 RidgeRun (todd.fischer@ridgerun.com)
531dd6a26STodd Fischer  *
631dd6a26STodd Fischer  * Author: Todd Fischer
731dd6a26STodd Fischer  *         todd.fischer@ridgerun.com
831dd6a26STodd Fischer  *
931dd6a26STodd Fischer  * Credits:
1031dd6a26STodd Fischer  *
1131dd6a26STodd Fischer  *    Using code from wm831x-*.c, wm8400-core, Wolfson Microelectronics PLC.
1231dd6a26STodd Fischer  *
1331dd6a26STodd Fischer  * For licencing details see kernel-base/COPYING
1431dd6a26STodd Fischer  *
1531dd6a26STodd Fischer  */
1631dd6a26STodd Fischer 
1731dd6a26STodd Fischer #include <linux/module.h>
1831dd6a26STodd Fischer #include <linux/moduleparam.h>
1931dd6a26STodd Fischer #include <linux/init.h>
2031dd6a26STodd Fischer #include <linux/slab.h>
2131dd6a26STodd Fischer #include <linux/i2c.h>
225c8c8794SSachin Kamat #include <linux/of.h>
2331dd6a26STodd Fischer #include <linux/mfd/core.h>
2431dd6a26STodd Fischer #include <linux/mfd/tps6507x.h>
2531dd6a26STodd Fischer 
2630fe2b5bSGeert Uytterhoeven static const struct mfd_cell tps6507x_devs[] = {
2731dd6a26STodd Fischer 	{
2831dd6a26STodd Fischer 		.name = "tps6507x-pmic",
2931dd6a26STodd Fischer 	},
3075259966STodd Fischer 	{
3175259966STodd Fischer 		.name = "tps6507x-ts",
3275259966STodd Fischer 	},
3331dd6a26STodd Fischer };
3431dd6a26STodd Fischer 
3531dd6a26STodd Fischer 
tps6507x_i2c_read_device(struct tps6507x_dev * tps6507x,char reg,int bytes,void * dest)3631dd6a26STodd Fischer static int tps6507x_i2c_read_device(struct tps6507x_dev *tps6507x, char reg,
3731dd6a26STodd Fischer 				  int bytes, void *dest)
3831dd6a26STodd Fischer {
3931dd6a26STodd Fischer 	struct i2c_client *i2c = tps6507x->i2c_client;
4031dd6a26STodd Fischer 	struct i2c_msg xfer[2];
4131dd6a26STodd Fischer 	int ret;
4231dd6a26STodd Fischer 
4331dd6a26STodd Fischer 	/* Write register */
4431dd6a26STodd Fischer 	xfer[0].addr = i2c->addr;
4531dd6a26STodd Fischer 	xfer[0].flags = 0;
4631dd6a26STodd Fischer 	xfer[0].len = 1;
4731dd6a26STodd Fischer 	xfer[0].buf = &reg;
4831dd6a26STodd Fischer 
4931dd6a26STodd Fischer 	/* Read data */
5031dd6a26STodd Fischer 	xfer[1].addr = i2c->addr;
5131dd6a26STodd Fischer 	xfer[1].flags = I2C_M_RD;
5231dd6a26STodd Fischer 	xfer[1].len = bytes;
5331dd6a26STodd Fischer 	xfer[1].buf = dest;
5431dd6a26STodd Fischer 
5531dd6a26STodd Fischer 	ret = i2c_transfer(i2c->adapter, xfer, 2);
5631dd6a26STodd Fischer 	if (ret == 2)
5731dd6a26STodd Fischer 		ret = 0;
5831dd6a26STodd Fischer 	else if (ret >= 0)
5931dd6a26STodd Fischer 		ret = -EIO;
6031dd6a26STodd Fischer 
6131dd6a26STodd Fischer 	return ret;
6231dd6a26STodd Fischer }
6331dd6a26STodd Fischer 
tps6507x_i2c_write_device(struct tps6507x_dev * tps6507x,char reg,int bytes,void * src)6431dd6a26STodd Fischer static int tps6507x_i2c_write_device(struct tps6507x_dev *tps6507x, char reg,
6531dd6a26STodd Fischer 				   int bytes, void *src)
6631dd6a26STodd Fischer {
6731dd6a26STodd Fischer 	struct i2c_client *i2c = tps6507x->i2c_client;
6831dd6a26STodd Fischer 	/* we add 1 byte for device register */
6931dd6a26STodd Fischer 	u8 msg[TPS6507X_MAX_REGISTER + 1];
7031dd6a26STodd Fischer 	int ret;
7131dd6a26STodd Fischer 
72a8d6aa08SAxel Lin 	if (bytes > TPS6507X_MAX_REGISTER)
7331dd6a26STodd Fischer 		return -EINVAL;
7431dd6a26STodd Fischer 
7531dd6a26STodd Fischer 	msg[0] = reg;
7631dd6a26STodd Fischer 	memcpy(&msg[1], src, bytes);
7731dd6a26STodd Fischer 
7831dd6a26STodd Fischer 	ret = i2c_master_send(i2c, msg, bytes + 1);
7931dd6a26STodd Fischer 	if (ret < 0)
8031dd6a26STodd Fischer 		return ret;
8131dd6a26STodd Fischer 	if (ret != bytes + 1)
8231dd6a26STodd Fischer 		return -EIO;
8331dd6a26STodd Fischer 	return 0;
8431dd6a26STodd Fischer }
8531dd6a26STodd Fischer 
tps6507x_i2c_probe(struct i2c_client * i2c)860e1a8964SUwe Kleine-König static int tps6507x_i2c_probe(struct i2c_client *i2c)
8731dd6a26STodd Fischer {
8831dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x;
8931dd6a26STodd Fischer 
901881b68bSAxel Lin 	tps6507x = devm_kzalloc(&i2c->dev, sizeof(struct tps6507x_dev),
911881b68bSAxel Lin 				GFP_KERNEL);
9204a06423SAxel Lin 	if (tps6507x == NULL)
9331dd6a26STodd Fischer 		return -ENOMEM;
9431dd6a26STodd Fischer 
9531dd6a26STodd Fischer 	i2c_set_clientdata(i2c, tps6507x);
9631dd6a26STodd Fischer 	tps6507x->dev = &i2c->dev;
9731dd6a26STodd Fischer 	tps6507x->i2c_client = i2c;
9831dd6a26STodd Fischer 	tps6507x->read_dev = tps6507x_i2c_read_device;
9931dd6a26STodd Fischer 	tps6507x->write_dev = tps6507x_i2c_write_device;
10031dd6a26STodd Fischer 
1015635d994SLaxman Dewangan 	return devm_mfd_add_devices(tps6507x->dev, -1, tps6507x_devs,
1021881b68bSAxel Lin 				    ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL);
10331dd6a26STodd Fischer }
10431dd6a26STodd Fischer 
10531dd6a26STodd Fischer static const struct i2c_device_id tps6507x_i2c_id[] = {
10631dd6a26STodd Fischer 	{ "tps6507x", 0 },
10731dd6a26STodd Fischer 	{ }
10831dd6a26STodd Fischer };
10931dd6a26STodd Fischer MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
11031dd6a26STodd Fischer 
111154c4c7bSVishwanathrao Badarkhe, Manish #ifdef CONFIG_OF
112153a4ff4SJingoo Han static const struct of_device_id tps6507x_of_match[] = {
113154c4c7bSVishwanathrao Badarkhe, Manish 	{.compatible = "ti,tps6507x", },
114154c4c7bSVishwanathrao Badarkhe, Manish 	{},
115154c4c7bSVishwanathrao Badarkhe, Manish };
116154c4c7bSVishwanathrao Badarkhe, Manish MODULE_DEVICE_TABLE(of, tps6507x_of_match);
117154c4c7bSVishwanathrao Badarkhe, Manish #endif
11831dd6a26STodd Fischer 
11931dd6a26STodd Fischer static struct i2c_driver tps6507x_i2c_driver = {
12031dd6a26STodd Fischer 	.driver = {
12131dd6a26STodd Fischer 		   .name = "tps6507x",
122154c4c7bSVishwanathrao Badarkhe, Manish 		   .of_match_table = of_match_ptr(tps6507x_of_match),
12331dd6a26STodd Fischer 	},
124*9816d859SUwe Kleine-König 	.probe = tps6507x_i2c_probe,
12531dd6a26STodd Fischer 	.id_table = tps6507x_i2c_id,
12631dd6a26STodd Fischer };
12731dd6a26STodd Fischer 
tps6507x_i2c_init(void)12831dd6a26STodd Fischer static int __init tps6507x_i2c_init(void)
12931dd6a26STodd Fischer {
13031dd6a26STodd Fischer 	return i2c_add_driver(&tps6507x_i2c_driver);
13131dd6a26STodd Fischer }
13231dd6a26STodd Fischer /* init early so consumer devices can complete system boot */
13331dd6a26STodd Fischer subsys_initcall(tps6507x_i2c_init);
13431dd6a26STodd Fischer 
tps6507x_i2c_exit(void)13531dd6a26STodd Fischer static void __exit tps6507x_i2c_exit(void)
13631dd6a26STodd Fischer {
13731dd6a26STodd Fischer 	i2c_del_driver(&tps6507x_i2c_driver);
13831dd6a26STodd Fischer }
13931dd6a26STodd Fischer module_exit(tps6507x_i2c_exit);
14031dd6a26STodd Fischer 
14131dd6a26STodd Fischer MODULE_DESCRIPTION("TPS6507x chip family multi-function driver");
14231dd6a26STodd Fischer MODULE_LICENSE("GPL");
143