1/*
2 * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
3 *
4 * Enter bugs at http://blackfin.uclinux.org/
5 *
6 * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
7 * Licensed under the GPL-2 or later.
8 */
9
10#include <linux/input.h>	/* BUS_I2C */
11#include <linux/i2c.h>
12#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/pm.h>
15#include "adxl34x.h"
16
17static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
18{
19	struct i2c_client *client = to_i2c_client(dev);
20
21	return i2c_smbus_read_byte_data(client, reg);
22}
23
24static int adxl34x_smbus_write(struct device *dev,
25			       unsigned char reg, unsigned char val)
26{
27	struct i2c_client *client = to_i2c_client(dev);
28
29	return i2c_smbus_write_byte_data(client, reg, val);
30}
31
32static int adxl34x_smbus_read_block(struct device *dev,
33				    unsigned char reg, int count,
34				    void *buf)
35{
36	struct i2c_client *client = to_i2c_client(dev);
37
38	return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
39}
40
41static int adxl34x_i2c_read_block(struct device *dev,
42				  unsigned char reg, int count,
43				  void *buf)
44{
45	struct i2c_client *client = to_i2c_client(dev);
46	int ret;
47
48	ret = i2c_master_send(client, &reg, 1);
49	if (ret < 0)
50		return ret;
51
52	ret = i2c_master_recv(client, buf, count);
53	if (ret < 0)
54		return ret;
55
56	if (ret != count)
57		return -EIO;
58
59	return 0;
60}
61
62static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
63	.bustype	= BUS_I2C,
64	.write		= adxl34x_smbus_write,
65	.read		= adxl34x_smbus_read,
66	.read_block	= adxl34x_smbus_read_block,
67};
68
69static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
70	.bustype	= BUS_I2C,
71	.write		= adxl34x_smbus_write,
72	.read		= adxl34x_smbus_read,
73	.read_block	= adxl34x_i2c_read_block,
74};
75
76static int adxl34x_i2c_probe(struct i2c_client *client,
77				       const struct i2c_device_id *id)
78{
79	struct adxl34x *ac;
80	int error;
81
82	error = i2c_check_functionality(client->adapter,
83			I2C_FUNC_SMBUS_BYTE_DATA);
84	if (!error) {
85		dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
86		return -EIO;
87	}
88
89	ac = adxl34x_probe(&client->dev, client->irq, false,
90			   i2c_check_functionality(client->adapter,
91						   I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
92				&adxl34x_smbus_bops : &adxl34x_i2c_bops);
93	if (IS_ERR(ac))
94		return PTR_ERR(ac);
95
96	i2c_set_clientdata(client, ac);
97
98	return 0;
99}
100
101static int adxl34x_i2c_remove(struct i2c_client *client)
102{
103	struct adxl34x *ac = i2c_get_clientdata(client);
104
105	return adxl34x_remove(ac);
106}
107
108static int __maybe_unused adxl34x_i2c_suspend(struct device *dev)
109{
110	struct i2c_client *client = to_i2c_client(dev);
111	struct adxl34x *ac = i2c_get_clientdata(client);
112
113	adxl34x_suspend(ac);
114
115	return 0;
116}
117
118static int __maybe_unused adxl34x_i2c_resume(struct device *dev)
119{
120	struct i2c_client *client = to_i2c_client(dev);
121	struct adxl34x *ac = i2c_get_clientdata(client);
122
123	adxl34x_resume(ac);
124
125	return 0;
126}
127
128static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend,
129			 adxl34x_i2c_resume);
130
131static const struct i2c_device_id adxl34x_id[] = {
132	{ "adxl34x", 0 },
133	{ }
134};
135
136MODULE_DEVICE_TABLE(i2c, adxl34x_id);
137
138static struct i2c_driver adxl34x_driver = {
139	.driver = {
140		.name = "adxl34x",
141		.owner = THIS_MODULE,
142		.pm = &adxl34x_i2c_pm,
143	},
144	.probe    = adxl34x_i2c_probe,
145	.remove   = adxl34x_i2c_remove,
146	.id_table = adxl34x_id,
147};
148
149module_i2c_driver(adxl34x_driver);
150
151MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
152MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
153MODULE_LICENSE("GPL");
154