blob: 0ad97fc7f56bb2e8243bd9a69d555b4d8788bf13 [file] [log] [blame]
Marc Olberding1e17db52025-08-27 12:25:28 -07001// SPDX-License-Identifier: Apache-2.0
Patrick Williams4a943522025-10-09 20:34:38 -04002// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Marc Olberding1e17db52025-08-27 12:25:28 -07003
4#include "i2c.hpp"
5
Marc Olberding5d50e522025-09-03 18:23:32 -07006#include <fcntl.h>
7#include <linux/i2c-dev.h>
8#include <sys/ioctl.h>
9#include <unistd.h>
10
11#include <filesystem>
Marc Olberding1e17db52025-08-27 12:25:28 -070012#include <format>
13#include <fstream>
14#include <iostream>
Marc Olberding5d50e522025-09-03 18:23:32 -070015
16extern "C"
17{
18#include <i2c/smbus.h>
19#include <linux/i2c-dev.h>
20}
21
Marc Olberding1e17db52025-08-27 12:25:28 -070022namespace i2c
23{
24
25void rebind_controller(std::string_view number)
26{
27 std::string bindpath =
28 std::format("/sys/bus/platform/drivers/aspeed-i2c-bus/unbind", number);
29 std::ofstream bindofs(bindpath);
30 if (!bindofs)
31 {
32 std::cerr << std::format("{} unable to open\n", bindpath);
33 return;
34 }
35 try
36 {
37 bindofs << std::format("{}.i2c\n", number);
38 }
39 catch (const std::system_error& e)
40 {
41 std::cerr << std::format("{} unable to write\n", bindpath);
42 return;
43 }
44 bindofs.close();
45 std::cerr << std::format("{} unbound\n", number);
46
47 std::string unbindpath =
48 std::format("/sys/bus/platform/drivers/aspeed-i2c-bus/bind", number);
49 std::ofstream unbindofs(unbindpath);
50 if (!unbindofs)
51 {
52 std::cerr << std::format("{} unable to open\n", unbindpath);
53 return;
54 }
55 try
56 {
57 unbindofs << std::format("{}.i2c\n", number);
58 }
59 catch (const std::system_error& e)
60 {
61 std::cerr << std::format("{} unable to write\n", unbindpath);
62 return;
63 }
64 std::cerr << std::format("{} bound\n", number);
65}
66
67void new_device(unsigned int bus, unsigned int address,
68 std::string_view device_type)
69{
70 std::string path =
71 std::format("/sys/bus/i2c/devices/i2c-{}/new_device", bus);
72 std::cerr << std::format("attempting to open {}", path);
73 std::ofstream new_device(path);
74 if (!new_device)
75 {
76 std::cerr << "Error: Unable to create I2C device\n";
77 return;
78 }
79 new_device << std::format("{} 0x{:02x}", device_type, address);
80 new_device.close();
81
82 std::cerr << std::format("{} device created at bus {}", device_type, bus);
83}
Marc Olberding5d50e522025-09-03 18:23:32 -070084
85RawDevice::RawDevice(size_t bus, uint8_t address)
86{
87 std::string bus_path = std::format("/dev/i2c-{}", bus);
88 std::filesystem::path dev_path = bus_path;
89 fd = open(dev_path.c_str(), O_RDWR);
90 if (fd < 0)
91 {
92 std::cerr << std::format("failed to open {}\n", dev_path.native());
93 throw std::runtime_error(
94 std::format("Failed to open {}", dev_path.native()));
95 }
96
97 if (ioctl(fd, I2C_SLAVE, address) < 0)
98 {
99 // dtor won't be called since we never finished constructing it, clean
100 // up our fd
101 close(fd);
102 throw std::runtime_error(
103 std::format("Failed to specify address {}", address));
104 }
105}
106
107RawDevice::~RawDevice()
108{
109 close(fd);
110}
111
112int RawDevice::read_byte(uint8_t reg, uint8_t& val)
113{
114 int result = i2c_smbus_read_byte_data(fd, reg);
115 if (result < 0)
116 {
117 return -result;
118 }
119
120 val = result;
121 return 0;
122}
123
Marc Olberding1e17db52025-08-27 12:25:28 -0700124} // namespace i2c