summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/mfd/tps65912-i2c.c
blob: 6a6343ee95fe7dd1d9b7630e53c0e1fff2a07f40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * tps65912-i2c.c  --  I2C access for TI TPS65912x PMIC
 *
 * Copyright 2011 Texas Instruments Inc.
 *
 * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk>
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under  the terms of the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the License, or (at your
 *  option) any later version.
 *
 *  This driver is based on wm8350 implementation.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65912.h>

static int tps65912_i2c_read(struct tps65912 *tps65912, u8 reg,
				  int bytes, void *dest)
{
	struct i2c_client *i2c = tps65912->control_data;
	struct i2c_msg xfer[2];
	int ret;

	/* Write register */
	xfer[0].addr = i2c->addr;
	xfer[0].flags = 0;
	xfer[0].len = 1;
	xfer[0].buf = &reg;

	/* Read data */
	xfer[1].addr = i2c->addr;
	xfer[1].flags = I2C_M_RD;
	xfer[1].len = bytes;
	xfer[1].buf = dest;

	ret = i2c_transfer(i2c->adapter, xfer, 2);
	if (ret == 2)
		ret = 0;
	else if (ret >= 0)
		ret = -EIO;
	return ret;
}

static int tps65912_i2c_write(struct tps65912 *tps65912, u8 reg,
				   int bytes, void *src)
{
	struct i2c_client *i2c = tps65912->control_data;
	/* we add 1 byte for device register */
	u8 msg[TPS6591X_MAX_REGISTER + 1];
	int ret;

	if (bytes > TPS6591X_MAX_REGISTER)
		return -EINVAL;

	msg[0] = reg;
	memcpy(&msg[1], src, bytes);

	ret = i2c_master_send(i2c, msg, bytes + 1);
	if (ret < 0)
		return ret;
	if (ret != bytes + 1)
		return -EIO;

	return 0;
}

static int tps65912_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct tps65912 *tps65912;

	tps65912 = devm_kzalloc(&i2c->dev,
				sizeof(struct tps65912), GFP_KERNEL);
	if (tps65912 == NULL)
		return -ENOMEM;

	i2c_set_clientdata(i2c, tps65912);
	tps65912->dev = &i2c->dev;
	tps65912->control_data = i2c;
	tps65912->read = tps65912_i2c_read;
	tps65912->write = tps65912_i2c_write;

	return tps65912_device_init(tps65912);
}

static int tps65912_i2c_remove(struct i2c_client *i2c)
{
	struct tps65912 *tps65912 = i2c_get_clientdata(i2c);

	tps65912_device_exit(tps65912);

	return 0;
}

static const struct i2c_device_id tps65912_i2c_id[] = {
	{"tps65912", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id);

static struct i2c_driver tps65912_i2c_driver = {
	.driver = {
		   .name = "tps65912",
		   .owner = THIS_MODULE,
	},
	.probe = tps65912_i2c_probe,
	.remove = tps65912_i2c_remove,
	.id_table = tps65912_i2c_id,
};

static int __init tps65912_i2c_init(void)
{
	int ret;

	ret = i2c_add_driver(&tps65912_i2c_driver);
	if (ret != 0)
		pr_err("Failed to register TPS65912 I2C driver: %d\n", ret);

	return ret;
}
/* init early so consumer devices can complete system boot */
subsys_initcall(tps65912_i2c_init);

static void __exit tps65912_i2c_exit(void)
{
	i2c_del_driver(&tps65912_i2c_driver);
}
module_exit(tps65912_i2c_exit);

MODULE_AUTHOR("Margarita Olaya	<magi@slimlogic.co.uk>");
MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
MODULE_LICENSE("GPL");