1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface) |
4 | * |
5 | * Enter bugs at http://blackfin.uclinux.org/ |
6 | * |
7 | * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc. |
8 | */ |
9 | |
10 | #include <linux/input.h> /* BUS_I2C */ |
11 | #include <linux/i2c.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/types.h> |
15 | #include <linux/pm.h> |
16 | #include "adxl34x.h" |
17 | |
18 | static int adxl34x_smbus_read(struct device *dev, unsigned char reg) |
19 | { |
20 | struct i2c_client *client = to_i2c_client(dev); |
21 | |
22 | return i2c_smbus_read_byte_data(client, command: reg); |
23 | } |
24 | |
25 | static int adxl34x_smbus_write(struct device *dev, |
26 | unsigned char reg, unsigned char val) |
27 | { |
28 | struct i2c_client *client = to_i2c_client(dev); |
29 | |
30 | return i2c_smbus_write_byte_data(client, command: reg, value: val); |
31 | } |
32 | |
33 | static int adxl34x_smbus_read_block(struct device *dev, |
34 | unsigned char reg, int count, |
35 | void *buf) |
36 | { |
37 | struct i2c_client *client = to_i2c_client(dev); |
38 | |
39 | return i2c_smbus_read_i2c_block_data(client, command: reg, length: count, values: buf); |
40 | } |
41 | |
42 | static int adxl34x_i2c_read_block(struct device *dev, |
43 | unsigned char reg, int count, |
44 | void *buf) |
45 | { |
46 | struct i2c_client *client = to_i2c_client(dev); |
47 | int ret; |
48 | |
49 | ret = i2c_master_send(client, buf: ®, count: 1); |
50 | if (ret < 0) |
51 | return ret; |
52 | |
53 | ret = i2c_master_recv(client, buf, count); |
54 | if (ret < 0) |
55 | return ret; |
56 | |
57 | if (ret != count) |
58 | return -EIO; |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | static const struct adxl34x_bus_ops adxl34x_smbus_bops = { |
64 | .bustype = BUS_I2C, |
65 | .write = adxl34x_smbus_write, |
66 | .read = adxl34x_smbus_read, |
67 | .read_block = adxl34x_smbus_read_block, |
68 | }; |
69 | |
70 | static const struct adxl34x_bus_ops adxl34x_i2c_bops = { |
71 | .bustype = BUS_I2C, |
72 | .write = adxl34x_smbus_write, |
73 | .read = adxl34x_smbus_read, |
74 | .read_block = adxl34x_i2c_read_block, |
75 | }; |
76 | |
77 | static int adxl34x_i2c_probe(struct i2c_client *client) |
78 | { |
79 | struct adxl34x *ac; |
80 | int error; |
81 | |
82 | error = i2c_check_functionality(adap: 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(dev: &client->dev, irq: client->irq, fifo_delay_default: false, |
90 | bops: i2c_check_functionality(adap: client->adapter, |
91 | I2C_FUNC_SMBUS_READ_I2C_BLOCK) ? |
92 | &adxl34x_smbus_bops : &adxl34x_i2c_bops); |
93 | if (IS_ERR(ptr: ac)) |
94 | return PTR_ERR(ptr: ac); |
95 | |
96 | i2c_set_clientdata(client, data: ac); |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | static void adxl34x_i2c_remove(struct i2c_client *client) |
102 | { |
103 | struct adxl34x *ac = i2c_get_clientdata(client); |
104 | |
105 | adxl34x_remove(ac); |
106 | } |
107 | |
108 | static const struct i2c_device_id adxl34x_id[] = { |
109 | { "adxl34x" , 0 }, |
110 | { } |
111 | }; |
112 | |
113 | MODULE_DEVICE_TABLE(i2c, adxl34x_id); |
114 | |
115 | static const struct of_device_id adxl34x_of_id[] = { |
116 | /* |
117 | * The ADXL346 is backward-compatible with the ADXL345. Differences are |
118 | * handled by runtime detection of the device model, there's thus no |
119 | * need for listing the "adi,adxl346" compatible value explicitly. |
120 | */ |
121 | { .compatible = "adi,adxl345" , }, |
122 | /* |
123 | * Deprecated, DT nodes should use one or more of the device-specific |
124 | * compatible values "adi,adxl345" and "adi,adxl346". |
125 | */ |
126 | { .compatible = "adi,adxl34x" , }, |
127 | { } |
128 | }; |
129 | |
130 | MODULE_DEVICE_TABLE(of, adxl34x_of_id); |
131 | |
132 | static struct i2c_driver adxl34x_driver = { |
133 | .driver = { |
134 | .name = "adxl34x" , |
135 | .pm = pm_sleep_ptr(&adxl34x_pm), |
136 | .of_match_table = adxl34x_of_id, |
137 | }, |
138 | .probe = adxl34x_i2c_probe, |
139 | .remove = adxl34x_i2c_remove, |
140 | .id_table = adxl34x_id, |
141 | }; |
142 | |
143 | module_i2c_driver(adxl34x_driver); |
144 | |
145 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>" ); |
146 | MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver" ); |
147 | MODULE_LICENSE("GPL" ); |
148 | |