1/*
2 * Copyright 2020, J��r��me Duval, jerome.duval@gmail.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "I2CPrivate.h"
8
9
10I2CBus::I2CBus(device_node *node, uint8 id)
11	:
12	fNode(node),
13	fID(id),
14	fController(NULL),
15	fCookie(NULL)
16{
17	CALLED();
18	device_node *parent = gDeviceManager->get_parent_node(node);
19	status_t status = gDeviceManager->get_driver(parent,
20		(driver_module_info **)&fController, &fCookie);
21	gDeviceManager->put_node(parent);
22
23	if (status != B_OK)
24		return;
25
26	fController->set_i2c_bus(fCookie, this);
27
28}
29
30
31I2CBus::~I2CBus()
32{
33}
34
35
36status_t
37I2CBus::InitCheck()
38{
39	return B_OK;
40}
41
42
43status_t
44I2CBus::ExecCommand(i2c_op op, i2c_addr slaveAddress, const void *cmdBuffer,
45	size_t cmdLength, void* dataBuffer, size_t dataLength)
46{
47	CALLED();
48	return fController->exec_command(fCookie, op, slaveAddress, cmdBuffer, cmdLength,
49		dataBuffer, dataLength);
50}
51
52
53status_t
54I2CBus::RegisterDevice(i2c_addr slaveAddress, char* hid, char** cid,
55	acpi_handle acpiHandle)
56{
57	CALLED();
58
59	device_attr attrs[] = {
60		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "I2C device" }},
61
62		// connection
63		{ I2C_DEVICE_SLAVE_ADDR_ITEM, B_UINT16_TYPE, { .ui16 = slaveAddress }},
64
65		// description of peripheral drivers
66		{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "i2c" }},
67
68		{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
69
70		{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = hid }},
71
72		{ ACPI_DEVICE_CID_ITEM, B_STRING_TYPE, { .string = cid[0] }},
73
74		{ ACPI_DEVICE_HANDLE_ITEM, B_UINT64_TYPE, { .ui64 = (addr_t)acpiHandle }},
75
76		{ NULL }
77	};
78
79	return gDeviceManager->register_node(fNode, I2C_DEVICE_MODULE_NAME, attrs,
80		NULL, NULL);
81}
82
83
84status_t
85I2CBus::Scan()
86{
87	CALLED();
88	if (fController->scan_bus != NULL)
89		fController->scan_bus(fCookie);
90	return B_OK;
91}
92
93
94status_t
95I2CBus::AcquireBus()
96{
97	CALLED();
98	if (fController->acquire_bus != NULL)
99		return fController->acquire_bus(fCookie);
100	return B_OK;
101}
102
103
104void
105I2CBus::ReleaseBus()
106{
107	CALLED();
108	if (fController->release_bus != NULL)
109		fController->release_bus(fCookie);
110}
111
112
113static status_t
114i2c_init_bus(device_node *node, void **_bus)
115{
116	CALLED();
117	uint8 pathID;
118	if (gDeviceManager->get_attr_uint8(node, I2C_BUS_PATH_ID_ITEM, &pathID,
119		false) != B_OK) {
120		return B_ERROR;
121	}
122
123	I2CBus *bus = new(std::nothrow) I2CBus(node, pathID);
124	if (bus == NULL)
125		return B_NO_MEMORY;
126
127	status_t result = bus->InitCheck();
128	if (result != B_OK) {
129		ERROR("failed to set up i2c bus object\n");
130		return result;
131	}
132
133	*_bus = bus;
134
135	char name[128];
136	snprintf(name, sizeof(name), "bus/i2c/%d/bus_raw", pathID);
137
138	return gDeviceManager->publish_device(node, name, I2C_BUS_RAW_MODULE_NAME);
139}
140
141
142static void
143i2c_uninit_bus(void *_bus)
144{
145	CALLED();
146	I2CBus *bus = (I2CBus *)_bus;
147	delete bus;
148}
149
150
151static status_t
152i2c_scan_bus(void *_bus)
153{
154	I2CBus *bus = (I2CBus *)_bus;
155	return bus->Scan();
156}
157
158
159status_t
160i2c_bus_exec_command(void* _bus, i2c_op op, i2c_addr slaveAddress,
161		const void *cmdBuffer, size_t cmdLength, void* dataBuffer,
162		size_t dataLength)
163{
164	CALLED();
165	I2CBus* bus = (I2CBus*)_bus;
166	return bus->ExecCommand(op, slaveAddress, cmdBuffer, cmdLength,
167		dataBuffer, dataLength);
168}
169
170
171static status_t
172i2c_bus_acquire_bus(void* _bus)
173{
174	CALLED();
175	I2CBus* bus = (I2CBus*)_bus;
176	return bus->AcquireBus();
177}
178
179
180static void
181i2c_bus_release_bus(void* _bus)
182{
183	CALLED();
184	I2CBus* bus = (I2CBus*)_bus;
185	return bus->ReleaseBus();
186}
187
188
189static status_t
190std_ops(int32 op, ...)
191{
192	switch (op) {
193		case B_MODULE_INIT:
194		case B_MODULE_UNINIT:
195			return B_OK;
196
197		default:
198			break;
199	}
200
201	return B_ERROR;
202}
203
204
205i2c_bus_interface gI2CBusModule = {
206	{
207		{
208			I2C_BUS_MODULE_NAME,
209			0,
210			std_ops
211		},
212
213		NULL, // supported devices
214		NULL, // register node
215		i2c_init_bus,
216		i2c_uninit_bus,
217		i2c_scan_bus, // register child devices
218		NULL, // rescan
219	},
220
221	i2c_bus_exec_command,
222	i2c_bus_acquire_bus,
223	i2c_bus_release_bus,
224};
225
226