1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
// SPDX-License-Identifier: GPL-2.0
/*
* Core driver for Wilco Embedded Controller
*
* Copyright 2018 Google LLC
*
* This is the entry point for the drivers that control the Wilco EC.
* This driver is responsible for several tasks:
* - Initialize the register interface that is used by wilco_ec_mailbox()
* - Create a platform device which is picked up by the debugfs driver
* - Create a platform device which is picked up by the RTC driver
*/
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_data/wilco-ec.h>
#include <linux/platform_device.h>
#include "../cros_ec_lpc_mec.h"
#define DRV_NAME "wilco-ec"
static struct resource *wilco_get_resource(struct platform_device *pdev,
int index)
{
struct device *dev = &pdev->dev;
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_IO, index);
if (!res) {
dev_dbg(dev, "Couldn't find IO resource %d\n", index);
return res;
}
return devm_request_region(dev, res->start, resource_size(res),
dev_name(dev));
}
static int wilco_ec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct wilco_ec_device *ec;
ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
if (!ec)
return -ENOMEM;
platform_set_drvdata(pdev, ec);
ec->dev = dev;
mutex_init(&ec->mailbox_lock);
/* Largest data buffer size requirement is extended data response */
ec->data_size = sizeof(struct wilco_ec_response) +
EC_MAILBOX_DATA_SIZE_EXTENDED;
ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
if (!ec->data_buffer)
return -ENOMEM;
/* Prepare access to IO regions provided by ACPI */
ec->io_data = wilco_get_resource(pdev, 0); /* Host Data */
ec->io_command = wilco_get_resource(pdev, 1); /* Host Command */
ec->io_packet = wilco_get_resource(pdev, 2); /* MEC EMI */
if (!ec->io_data || !ec->io_command || !ec->io_packet)
return -ENODEV;
/* Initialize cros_ec register interface for communication */
cros_ec_lpc_mec_init(ec->io_packet->start,
ec->io_packet->start + EC_MAILBOX_DATA_SIZE);
return 0;
}
static int wilco_ec_remove(struct platform_device *pdev)
{
/* Teardown cros_ec interface */
cros_ec_lpc_mec_destroy();
return 0;
}
static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
{ "GOOG000C", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids);
static struct platform_driver wilco_ec_driver = {
.driver = {
.name = DRV_NAME,
.acpi_match_table = wilco_ec_acpi_device_ids,
},
.probe = wilco_ec_probe,
.remove = wilco_ec_remove,
};
module_platform_driver(wilco_ec_driver);
MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver");
MODULE_ALIAS("platform:" DRV_NAME);
|