Merge tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul...
[linux-2.6-microblaze.git] / drivers / i2c / busses / i2c-opal.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * IBM OPAL I2C driver
4  * Copyright (C) 2014 IBM
5  */
6
7 #include <linux/device.h>
8 #include <linux/i2c.h>
9 #include <linux/kernel.h>
10 #include <linux/mm.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
15
16 #include <asm/firmware.h>
17 #include <asm/opal.h>
18
19 static int i2c_opal_translate_error(int rc)
20 {
21         switch (rc) {
22         case OPAL_NO_MEM:
23                 return -ENOMEM;
24         case OPAL_PARAMETER:
25                 return -EINVAL;
26         case OPAL_I2C_ARBT_LOST:
27                 return -EAGAIN;
28         case OPAL_I2C_TIMEOUT:
29                 return -ETIMEDOUT;
30         case OPAL_I2C_NACK_RCVD:
31                 return -ENXIO;
32         case OPAL_I2C_STOP_ERR:
33                 return -EBUSY;
34         default:
35                 return -EIO;
36         }
37 }
38
39 static int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req)
40 {
41         struct opal_msg msg;
42         int token, rc;
43
44         token = opal_async_get_token_interruptible();
45         if (token < 0) {
46                 if (token != -ERESTARTSYS)
47                         pr_err("Failed to get the async token\n");
48
49                 return token;
50         }
51
52         rc = opal_i2c_request(token, bus_id, req);
53         if (rc != OPAL_ASYNC_COMPLETION) {
54                 rc = i2c_opal_translate_error(rc);
55                 goto exit;
56         }
57
58         rc = opal_async_wait_response(token, &msg);
59         if (rc)
60                 goto exit;
61
62         rc = opal_get_async_rc(msg);
63         if (rc != OPAL_SUCCESS) {
64                 rc = i2c_opal_translate_error(rc);
65                 goto exit;
66         }
67
68 exit:
69         opal_async_release_token(token);
70         return rc;
71 }
72
73 static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
74                                 int num)
75 {
76         unsigned long opal_id = (unsigned long)adap->algo_data;
77         struct opal_i2c_request req;
78         int rc, i;
79
80         /* We only support fairly simple combinations here of one
81          * or two messages
82          */
83         memset(&req, 0, sizeof(req));
84         switch(num) {
85         case 1:
86                 req.type = (msgs[0].flags & I2C_M_RD) ?
87                         OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
88                 req.addr = cpu_to_be16(msgs[0].addr);
89                 req.size = cpu_to_be32(msgs[0].len);
90                 req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
91                 break;
92         case 2:
93                 req.type = (msgs[1].flags & I2C_M_RD) ?
94                         OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
95                 req.addr = cpu_to_be16(msgs[0].addr);
96                 req.subaddr_sz = msgs[0].len;
97                 for (i = 0; i < msgs[0].len; i++)
98                         req.subaddr = (req.subaddr << 8) | msgs[0].buf[i];
99                 req.subaddr = cpu_to_be32(req.subaddr);
100                 req.size = cpu_to_be32(msgs[1].len);
101                 req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf));
102                 break;
103         }
104
105         rc = i2c_opal_send_request(opal_id, &req);
106         if (rc)
107                 return rc;
108
109         return num;
110 }
111
112 static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
113                                unsigned short flags, char read_write,
114                                u8 command, int size, union i2c_smbus_data *data)
115 {
116         unsigned long opal_id = (unsigned long)adap->algo_data;
117         struct opal_i2c_request req;
118         u8 local[2];
119         int rc;
120
121         memset(&req, 0, sizeof(req));
122
123         req.addr = cpu_to_be16(addr);
124         switch (size) {
125         case I2C_SMBUS_BYTE:
126                 req.buffer_ra = cpu_to_be64(__pa(&data->byte));
127                 req.size = cpu_to_be32(1);
128                 fallthrough;
129         case I2C_SMBUS_QUICK:
130                 req.type = (read_write == I2C_SMBUS_READ) ?
131                         OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
132                 break;
133         case I2C_SMBUS_BYTE_DATA:
134                 req.buffer_ra = cpu_to_be64(__pa(&data->byte));
135                 req.size = cpu_to_be32(1);
136                 req.subaddr = cpu_to_be32(command);
137                 req.subaddr_sz = 1;
138                 req.type = (read_write == I2C_SMBUS_READ) ?
139                         OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
140                 break;
141         case I2C_SMBUS_WORD_DATA:
142                 if (!read_write) {
143                         local[0] = data->word & 0xff;
144                         local[1] = (data->word >> 8) & 0xff;
145                 }
146                 req.buffer_ra = cpu_to_be64(__pa(local));
147                 req.size = cpu_to_be32(2);
148                 req.subaddr = cpu_to_be32(command);
149                 req.subaddr_sz = 1;
150                 req.type = (read_write == I2C_SMBUS_READ) ?
151                         OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
152                 break;
153         case I2C_SMBUS_I2C_BLOCK_DATA:
154                 req.buffer_ra = cpu_to_be64(__pa(&data->block[1]));
155                 req.size = cpu_to_be32(data->block[0]);
156                 req.subaddr = cpu_to_be32(command);
157                 req.subaddr_sz = 1;
158                 req.type = (read_write == I2C_SMBUS_READ) ?
159                         OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
160                 break;
161         default:
162                 return -EINVAL;
163         }
164
165         rc = i2c_opal_send_request(opal_id, &req);
166         if (!rc && read_write && size == I2C_SMBUS_WORD_DATA) {
167                 data->word = ((u16)local[1]) << 8;
168                 data->word |= local[0];
169         }
170
171         return rc;
172 }
173
174 static u32 i2c_opal_func(struct i2c_adapter *adapter)
175 {
176         return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
177                I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
178                I2C_FUNC_SMBUS_I2C_BLOCK;
179 }
180
181 static const struct i2c_algorithm i2c_opal_algo = {
182         .master_xfer    = i2c_opal_master_xfer,
183         .smbus_xfer     = i2c_opal_smbus_xfer,
184         .functionality  = i2c_opal_func,
185 };
186
187 /*
188  * For two messages, we basically support simple smbus transactions of a
189  * write-then-anything.
190  */
191 static const struct i2c_adapter_quirks i2c_opal_quirks = {
192         .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
193         .max_comb_1st_msg_len = 4,
194 };
195
196 static int i2c_opal_probe(struct platform_device *pdev)
197 {
198         struct i2c_adapter      *adapter;
199         const char              *pname;
200         u32                     opal_id;
201         int                     rc;
202
203         if (!pdev->dev.of_node)
204                 return -ENODEV;
205
206         rc = of_property_read_u32(pdev->dev.of_node, "ibm,opal-id", &opal_id);
207         if (rc) {
208                 dev_err(&pdev->dev, "Missing ibm,opal-id property !\n");
209                 return -EIO;
210         }
211
212         adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
213         if (!adapter)
214                 return -ENOMEM;
215
216         adapter->algo = &i2c_opal_algo;
217         adapter->algo_data = (void *)(unsigned long)opal_id;
218         adapter->quirks = &i2c_opal_quirks;
219         adapter->dev.parent = &pdev->dev;
220         adapter->dev.of_node = of_node_get(pdev->dev.of_node);
221         pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
222         if (pname)
223                 strlcpy(adapter->name, pname, sizeof(adapter->name));
224         else
225                 strlcpy(adapter->name, "opal", sizeof(adapter->name));
226
227         platform_set_drvdata(pdev, adapter);
228         rc = i2c_add_adapter(adapter);
229         if (rc)
230                 dev_err(&pdev->dev, "Failed to register the i2c adapter\n");
231
232         return rc;
233 }
234
235 static int i2c_opal_remove(struct platform_device *pdev)
236 {
237         struct i2c_adapter *adapter = platform_get_drvdata(pdev);
238
239         i2c_del_adapter(adapter);
240
241         return 0;
242 }
243
244 static const struct of_device_id i2c_opal_of_match[] = {
245         {
246                 .compatible = "ibm,opal-i2c",
247         },
248         { }
249 };
250 MODULE_DEVICE_TABLE(of, i2c_opal_of_match);
251
252 static struct platform_driver i2c_opal_driver = {
253         .probe  = i2c_opal_probe,
254         .remove = i2c_opal_remove,
255         .driver = {
256                 .name           = "i2c-opal",
257                 .of_match_table = i2c_opal_of_match,
258         },
259 };
260
261 static int __init i2c_opal_init(void)
262 {
263         if (!firmware_has_feature(FW_FEATURE_OPAL))
264                 return -ENODEV;
265
266         return platform_driver_register(&i2c_opal_driver);
267 }
268 module_init(i2c_opal_init);
269
270 static void __exit i2c_opal_exit(void)
271 {
272         return platform_driver_unregister(&i2c_opal_driver);
273 }
274 module_exit(i2c_opal_exit);
275
276 MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
277 MODULE_DESCRIPTION("IBM OPAL I2C driver");
278 MODULE_LICENSE("GPL");