forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/platform/olpc/olpc-ec.c
....@@ -1,11 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Generic driver for the OLPC Embedded Controller.
34 *
45 * Author: Andres Salomon <dilinger@queued.net>
56 *
67 * Copyright (C) 2011-2012 One Laptop per Child Foundation.
7
- *
8
- * Licensed under the GPL v2 or later.
98 */
109 #include <linux/completion.h>
1110 #include <linux/debugfs.h>
....@@ -16,8 +15,8 @@
1615 #include <linux/workqueue.h>
1716 #include <linux/init.h>
1817 #include <linux/list.h>
18
+#include <linux/regulator/driver.h>
1919 #include <linux/olpc-ec.h>
20
-#include <asm/olpc.h>
2120
2221 struct ec_cmd_desc {
2322 u8 cmd;
....@@ -33,14 +32,25 @@
3332
3433 struct olpc_ec_priv {
3534 struct olpc_ec_driver *drv;
35
+ u8 version;
3636 struct work_struct worker;
3737 struct mutex cmd_lock;
38
+
39
+ /* DCON regulator */
40
+ struct regulator_dev *dcon_rdev;
41
+ bool dcon_enabled;
3842
3943 /* Pending EC commands */
4044 struct list_head cmd_q;
4145 spinlock_t cmd_q_lock;
4246
4347 struct dentry *dbgfs_dir;
48
+
49
+ /*
50
+ * EC event mask to be applied during suspend (defining wakeup
51
+ * sources).
52
+ */
53
+ u16 ec_wakeup_mask;
4454
4555 /*
4656 * Running an EC command while suspending means we don't always finish
....@@ -119,8 +129,11 @@
119129 struct olpc_ec_priv *ec = ec_priv;
120130 struct ec_cmd_desc desc;
121131
122
- /* Ensure a driver and ec hook have been registered */
123
- if (WARN_ON(!ec_driver || !ec_driver->ec_cmd))
132
+ /* Driver not yet registered. */
133
+ if (!ec_driver)
134
+ return -EPROBE_DEFER;
135
+
136
+ if (WARN_ON(!ec_driver->ec_cmd))
124137 return -ENODEV;
125138
126139 if (!ec)
....@@ -150,6 +163,88 @@
150163 }
151164 EXPORT_SYMBOL_GPL(olpc_ec_cmd);
152165
166
+void olpc_ec_wakeup_set(u16 value)
167
+{
168
+ struct olpc_ec_priv *ec = ec_priv;
169
+
170
+ if (WARN_ON(!ec))
171
+ return;
172
+
173
+ ec->ec_wakeup_mask |= value;
174
+}
175
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set);
176
+
177
+void olpc_ec_wakeup_clear(u16 value)
178
+{
179
+ struct olpc_ec_priv *ec = ec_priv;
180
+
181
+ if (WARN_ON(!ec))
182
+ return;
183
+
184
+ ec->ec_wakeup_mask &= ~value;
185
+}
186
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear);
187
+
188
+int olpc_ec_mask_write(u16 bits)
189
+{
190
+ struct olpc_ec_priv *ec = ec_priv;
191
+
192
+ if (WARN_ON(!ec))
193
+ return -ENODEV;
194
+
195
+ /* EC version 0x5f adds support for wide SCI mask */
196
+ if (ec->version >= 0x5f) {
197
+ __be16 ec_word = cpu_to_be16(bits);
198
+
199
+ return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *)&ec_word, 2, NULL, 0);
200
+ } else {
201
+ u8 ec_byte = bits & 0xff;
202
+
203
+ return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0);
204
+ }
205
+}
206
+EXPORT_SYMBOL_GPL(olpc_ec_mask_write);
207
+
208
+/*
209
+ * Returns true if the compile and runtime configurations allow for EC events
210
+ * to wake the system.
211
+ */
212
+bool olpc_ec_wakeup_available(void)
213
+{
214
+ if (WARN_ON(!ec_driver))
215
+ return false;
216
+
217
+ return ec_driver->wakeup_available;
218
+}
219
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available);
220
+
221
+int olpc_ec_sci_query(u16 *sci_value)
222
+{
223
+ struct olpc_ec_priv *ec = ec_priv;
224
+ int ret;
225
+
226
+ if (WARN_ON(!ec))
227
+ return -ENODEV;
228
+
229
+ /* EC version 0x5f adds support for wide SCI mask */
230
+ if (ec->version >= 0x5f) {
231
+ __be16 ec_word;
232
+
233
+ ret = olpc_ec_cmd(EC_EXT_SCI_QUERY, NULL, 0, (void *)&ec_word, 2);
234
+ if (ret == 0)
235
+ *sci_value = be16_to_cpu(ec_word);
236
+ } else {
237
+ u8 ec_byte;
238
+
239
+ ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1);
240
+ if (ret == 0)
241
+ *sci_value = ec_byte;
242
+ }
243
+
244
+ return ret;
245
+}
246
+EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
247
+
153248 #ifdef CONFIG_DEBUG_FS
154249
155250 /*
....@@ -170,7 +265,7 @@
170265 int i, m;
171266 unsigned char ec_cmd[EC_MAX_CMD_ARGS];
172267 unsigned int ec_cmd_int[EC_MAX_CMD_ARGS];
173
- char cmdbuf[64];
268
+ char cmdbuf[64] = "";
174269 int ec_cmd_bytes;
175270
176271 mutex_lock(&ec_dbgfs_lock);
....@@ -255,9 +350,61 @@
255350
256351 #endif /* CONFIG_DEBUG_FS */
257352
353
+static int olpc_ec_set_dcon_power(struct olpc_ec_priv *ec, bool state)
354
+{
355
+ unsigned char ec_byte = state;
356
+ int ret;
357
+
358
+ if (ec->dcon_enabled == state)
359
+ return 0;
360
+
361
+ ret = olpc_ec_cmd(EC_DCON_POWER_MODE, &ec_byte, 1, NULL, 0);
362
+ if (ret)
363
+ return ret;
364
+
365
+ ec->dcon_enabled = state;
366
+ return 0;
367
+}
368
+
369
+static int dcon_regulator_enable(struct regulator_dev *rdev)
370
+{
371
+ struct olpc_ec_priv *ec = rdev_get_drvdata(rdev);
372
+
373
+ return olpc_ec_set_dcon_power(ec, true);
374
+}
375
+
376
+static int dcon_regulator_disable(struct regulator_dev *rdev)
377
+{
378
+ struct olpc_ec_priv *ec = rdev_get_drvdata(rdev);
379
+
380
+ return olpc_ec_set_dcon_power(ec, false);
381
+}
382
+
383
+static int dcon_regulator_is_enabled(struct regulator_dev *rdev)
384
+{
385
+ struct olpc_ec_priv *ec = rdev_get_drvdata(rdev);
386
+
387
+ return ec->dcon_enabled ? 1 : 0;
388
+}
389
+
390
+static struct regulator_ops dcon_regulator_ops = {
391
+ .enable = dcon_regulator_enable,
392
+ .disable = dcon_regulator_disable,
393
+ .is_enabled = dcon_regulator_is_enabled,
394
+};
395
+
396
+static const struct regulator_desc dcon_desc = {
397
+ .name = "dcon",
398
+ .id = 0,
399
+ .ops = &dcon_regulator_ops,
400
+ .type = REGULATOR_VOLTAGE,
401
+ .owner = THIS_MODULE,
402
+};
403
+
258404 static int olpc_ec_probe(struct platform_device *pdev)
259405 {
260406 struct olpc_ec_priv *ec;
407
+ struct regulator_config config = { };
261408 int err;
262409
263410 if (!ec_driver)
....@@ -277,14 +424,29 @@
277424 ec_priv = ec;
278425 platform_set_drvdata(pdev, ec);
279426
280
- err = ec_driver->probe ? ec_driver->probe(pdev) : 0;
281
- if (err) {
282
- ec_priv = NULL;
283
- kfree(ec);
284
- } else {
285
- ec->dbgfs_dir = olpc_ec_setup_debugfs();
427
+ /* get the EC revision */
428
+ err = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ec->version, 1);
429
+ if (err)
430
+ goto error;
431
+
432
+ config.dev = pdev->dev.parent;
433
+ config.driver_data = ec;
434
+ ec->dcon_enabled = true;
435
+ ec->dcon_rdev = devm_regulator_register(&pdev->dev, &dcon_desc,
436
+ &config);
437
+ if (IS_ERR(ec->dcon_rdev)) {
438
+ dev_err(&pdev->dev, "failed to register DCON regulator\n");
439
+ err = PTR_ERR(ec->dcon_rdev);
440
+ goto error;
286441 }
287442
443
+ ec->dbgfs_dir = olpc_ec_setup_debugfs();
444
+
445
+ return 0;
446
+
447
+error:
448
+ ec_priv = NULL;
449
+ kfree(ec);
288450 return err;
289451 }
290452
....@@ -294,6 +456,8 @@
294456 struct olpc_ec_priv *ec = platform_get_drvdata(pdev);
295457 int err = 0;
296458
459
+ olpc_ec_mask_write(ec->ec_wakeup_mask);
460
+
297461 if (ec_driver->suspend)
298462 err = ec_driver->suspend(pdev);
299463 if (!err)