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 = ®
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