1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ST Microelectronics MFD: stmpe's i2c client specific driver |
4 | * |
5 | * Copyright (C) ST-Ericsson SA 2010 |
6 | * Copyright (C) ST Microelectronics SA 2011 |
7 | * |
8 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson |
9 | * Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics |
10 | */ |
11 | |
12 | #include <linux/i2c.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> |
16 | #include <linux/types.h> |
17 | #include <linux/of_device.h> |
18 | #include "stmpe.h" |
19 | |
20 | static int i2c_reg_read(struct stmpe *stmpe, u8 reg) |
21 | { |
22 | struct i2c_client *i2c = stmpe->client; |
23 | |
24 | return i2c_smbus_read_byte_data(client: i2c, command: reg); |
25 | } |
26 | |
27 | static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val) |
28 | { |
29 | struct i2c_client *i2c = stmpe->client; |
30 | |
31 | return i2c_smbus_write_byte_data(client: i2c, command: reg, value: val); |
32 | } |
33 | |
34 | static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) |
35 | { |
36 | struct i2c_client *i2c = stmpe->client; |
37 | |
38 | return i2c_smbus_read_i2c_block_data(client: i2c, command: reg, length, values); |
39 | } |
40 | |
41 | static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length, |
42 | const u8 *values) |
43 | { |
44 | struct i2c_client *i2c = stmpe->client; |
45 | |
46 | return i2c_smbus_write_i2c_block_data(client: i2c, command: reg, length, values); |
47 | } |
48 | |
49 | static struct stmpe_client_info i2c_ci = { |
50 | .read_byte = i2c_reg_read, |
51 | .write_byte = i2c_reg_write, |
52 | .read_block = i2c_block_read, |
53 | .write_block = i2c_block_write, |
54 | }; |
55 | |
56 | static const struct of_device_id stmpe_of_match[] = { |
57 | { .compatible = "st,stmpe610" , .data = (void *)STMPE610, }, |
58 | { .compatible = "st,stmpe801" , .data = (void *)STMPE801, }, |
59 | { .compatible = "st,stmpe811" , .data = (void *)STMPE811, }, |
60 | { .compatible = "st,stmpe1600" , .data = (void *)STMPE1600, }, |
61 | { .compatible = "st,stmpe1601" , .data = (void *)STMPE1601, }, |
62 | { .compatible = "st,stmpe1801" , .data = (void *)STMPE1801, }, |
63 | { .compatible = "st,stmpe2401" , .data = (void *)STMPE2401, }, |
64 | { .compatible = "st,stmpe2403" , .data = (void *)STMPE2403, }, |
65 | {}, |
66 | }; |
67 | MODULE_DEVICE_TABLE(of, stmpe_of_match); |
68 | |
69 | static int |
70 | stmpe_i2c_probe(struct i2c_client *i2c) |
71 | { |
72 | const struct i2c_device_id *id = i2c_client_get_device_id(client: i2c); |
73 | enum stmpe_partnum partnum; |
74 | const struct of_device_id *of_id; |
75 | |
76 | i2c_ci.data = (void *)id; |
77 | i2c_ci.irq = i2c->irq; |
78 | i2c_ci.client = i2c; |
79 | i2c_ci.dev = &i2c->dev; |
80 | |
81 | of_id = of_match_device(matches: stmpe_of_match, dev: &i2c->dev); |
82 | if (!of_id) { |
83 | /* |
84 | * This happens when the I2C ID matches the node name |
85 | * but no real compatible string has been given. |
86 | */ |
87 | dev_info(&i2c->dev, "matching on node name, compatible is preferred\n" ); |
88 | partnum = id->driver_data; |
89 | } else |
90 | partnum = (uintptr_t)of_id->data; |
91 | |
92 | return stmpe_probe(ci: &i2c_ci, partnum); |
93 | } |
94 | |
95 | static void stmpe_i2c_remove(struct i2c_client *i2c) |
96 | { |
97 | struct stmpe *stmpe = dev_get_drvdata(dev: &i2c->dev); |
98 | |
99 | stmpe_remove(stmpe); |
100 | } |
101 | |
102 | static const struct i2c_device_id stmpe_i2c_id[] = { |
103 | { "stmpe610" , STMPE610 }, |
104 | { "stmpe801" , STMPE801 }, |
105 | { "stmpe811" , STMPE811 }, |
106 | { "stmpe1600" , STMPE1600 }, |
107 | { "stmpe1601" , STMPE1601 }, |
108 | { "stmpe1801" , STMPE1801 }, |
109 | { "stmpe2401" , STMPE2401 }, |
110 | { "stmpe2403" , STMPE2403 }, |
111 | { } |
112 | }; |
113 | MODULE_DEVICE_TABLE(i2c, stmpe_i2c_id); |
114 | |
115 | static struct i2c_driver stmpe_i2c_driver = { |
116 | .driver = { |
117 | .name = "stmpe-i2c" , |
118 | .pm = pm_sleep_ptr(&stmpe_dev_pm_ops), |
119 | .of_match_table = stmpe_of_match, |
120 | }, |
121 | .probe = stmpe_i2c_probe, |
122 | .remove = stmpe_i2c_remove, |
123 | .id_table = stmpe_i2c_id, |
124 | }; |
125 | |
126 | static int __init stmpe_init(void) |
127 | { |
128 | return i2c_add_driver(&stmpe_i2c_driver); |
129 | } |
130 | subsys_initcall(stmpe_init); |
131 | |
132 | static void __exit stmpe_exit(void) |
133 | { |
134 | i2c_del_driver(driver: &stmpe_i2c_driver); |
135 | } |
136 | module_exit(stmpe_exit); |
137 | |
138 | MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver" ); |
139 | MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>" ); |
140 | |