blob: d7ef7bb4974eb5fde9e9a02ba6848d6c75b261aa [file] [log] [blame]
Jim Wright1553cd92021-03-31 16:11:59 -05001/**
2 * Copyright © 2021 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jim Wright7945dd22021-04-06 16:55:15 -050017#include "ucd90320_monitor.hpp"
18
Jim Wright56ae78e2021-12-01 14:46:15 -060019#include "utility.hpp"
Jim Wright7945dd22021-04-06 16:55:15 -050020
Jim Wright56ae78e2021-12-01 14:46:15 -060021#include <fmt/format.h>
22#include <fmt/ranges.h>
23
Jim Wrightd8a86172021-12-08 11:38:26 -060024#include <nlohmann/json.hpp>
Jim Wright56ae78e2021-12-01 14:46:15 -060025#include <phosphor-logging/log.hpp>
26#include <sdbusplus/bus.hpp>
27
Jim Wrightd8a86172021-12-08 11:38:26 -060028#include <fstream>
Jim Wright56ae78e2021-12-01 14:46:15 -060029#include <map>
Jim Wright7945dd22021-04-06 16:55:15 -050030#include <string>
31
32namespace phosphor::power::sequencer
Jim Wright1553cd92021-03-31 16:11:59 -050033{
Jim Wright7945dd22021-04-06 16:55:15 -050034
Jim Wrightd8a86172021-12-08 11:38:26 -060035using json = nlohmann::json;
Jim Wright56ae78e2021-12-01 14:46:15 -060036using namespace phosphor::logging;
37using namespace phosphor::power;
38
39const std::string compatibleInterface =
40 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
41const std::string compatibleNamesProperty = "Names";
42
Jim Wright7945dd22021-04-06 16:55:15 -050043UCD90320Monitor::UCD90320Monitor(sdbusplus::bus::bus& bus, std::uint8_t i2cBus,
44 std::uint16_t i2cAddress) :
Jim Wright930458c2022-01-24 14:37:27 -060045 PowerSequencerMonitor(bus),
46 match{bus,
47 sdbusplus::bus::match::rules::interfacesAdded() +
48 sdbusplus::bus::match::rules::sender(
49 "xyz.openbmc_project.EntityManager"),
50 std::bind(&UCD90320Monitor::interfacesAddedHandler, this,
51 std::placeholders::_1)},
Jim Wright56ae78e2021-12-01 14:46:15 -060052 pmbusInterface{
53 fmt::format("/sys/bus/i2c/devices/{}-{:04x}", i2cBus, i2cAddress)
54 .c_str(),
55 "ucd9000", 0}
56
57{
58 // Use the compatible system types information, if already available, to
59 // load the configuration file
60 findCompatibleSystemTypes();
Jim Wright1553cd92021-03-31 16:11:59 -050061}
Jim Wright56ae78e2021-12-01 14:46:15 -060062
63void UCD90320Monitor::findCompatibleSystemTypes()
64{
65 try
66 {
67 auto subTree = util::getSubTree(bus, "/xyz/openbmc_project/inventory",
68 compatibleInterface, 0);
69
70 auto objectIt = subTree.cbegin();
71 if (objectIt != subTree.cend())
72 {
73 const auto& objPath = objectIt->first;
74
75 // Get the first service name
76 auto serviceIt = objectIt->second.cbegin();
77 if (serviceIt != objectIt->second.cend())
78 {
79 std::string service = serviceIt->first;
80 if (!service.empty())
81 {
82 std::vector<std::string> compatibleSystemTypes;
83
84 // Get compatible system types property value
85 util::getProperty(compatibleInterface,
86 compatibleNamesProperty, objPath, service,
87 bus, compatibleSystemTypes);
88
89 log<level::DEBUG>(
90 fmt::format("Found compatible systems: {}",
91 compatibleSystemTypes)
92 .c_str());
93 // Use compatible systems information to find config file
Jim Wrightd8a86172021-12-08 11:38:26 -060094 findConfigFile(compatibleSystemTypes);
Jim Wright56ae78e2021-12-01 14:46:15 -060095 }
96 }
97 }
98 }
99 catch (const std::exception&)
100 {
101 // Compatible system types information is not available.
102 }
103}
104
Jim Wrightd8a86172021-12-08 11:38:26 -0600105void UCD90320Monitor::findConfigFile(
106 const std::vector<std::string>& compatibleSystemTypes)
107{
108 // Expected config file path name:
109 // /usr/share/phosphor-power-sequencer/UCD90320Monitor_<systemType>.json
110
111 // Add possible file names based on compatible system types (if any)
112 for (const std::string& systemType : compatibleSystemTypes)
113 {
114 // Check if file exists
115 std::filesystem::path pathName{
116 "/usr/share/phosphor-power-sequencer/UCD90320Monitor_" +
117 systemType + ".json"};
118 if (std::filesystem::exists(pathName))
119 {
120 log<level::INFO>(
121 fmt::format("Config file path: {}", pathName.string()).c_str());
122 parseConfigFile(pathName);
123 break;
124 }
125 }
126}
127
Jim Wright56ae78e2021-12-01 14:46:15 -0600128void UCD90320Monitor::interfacesAddedHandler(sdbusplus::message::message& msg)
129{
Jim Wrightd8a86172021-12-08 11:38:26 -0600130 // Only continue if message is valid and rails / pins have not already been
131 // found
132 if (!msg || !rails.empty())
Jim Wright56ae78e2021-12-01 14:46:15 -0600133 {
134 return;
135 }
136
137 try
138 {
139 // Read the dbus message
140 sdbusplus::message::object_path objPath;
141 std::map<std::string,
142 std::map<std::string, std::variant<std::vector<std::string>>>>
143 interfaces;
144 msg.read(objPath, interfaces);
145
146 // Find the compatible interface, if present
147 auto itIntf = interfaces.find(compatibleInterface);
148 if (itIntf != interfaces.cend())
149 {
150 // Find the Names property of the compatible interface, if present
151 auto itProp = itIntf->second.find(compatibleNamesProperty);
152 if (itProp != itIntf->second.cend())
153 {
154 // Get value of Names property
155 const auto& propValue = std::get<0>(itProp->second);
156 if (!propValue.empty())
157 {
158 log<level::INFO>(
159 fmt::format(
160 "InterfacesAdded for compatible systems: {}",
161 propValue)
162 .c_str());
163
164 // Use compatible systems information to find config file
Jim Wrightd8a86172021-12-08 11:38:26 -0600165 findConfigFile(propValue);
Jim Wright56ae78e2021-12-01 14:46:15 -0600166 }
167 }
168 }
169 }
170 catch (const std::exception&)
171 {
172 // Error trying to read interfacesAdded message.
173 }
174}
Jim Wright7945dd22021-04-06 16:55:15 -0500175
Jim Wrightd8a86172021-12-08 11:38:26 -0600176void UCD90320Monitor::parseConfigFile(const std::filesystem::path& pathName)
177{
178 try
179 {
180 std::ifstream file{pathName};
181 json rootElement = json::parse(file);
182
183 // Parse rail information from config file
184 auto railsIterator = rootElement.find("rails");
185 if (railsIterator != rootElement.end())
186 {
187 for (const auto& railElement : *railsIterator)
188 {
189 std::string rail = railElement.get<std::string>();
190 rails.emplace_back(std::move(rail));
191 }
192 }
193 else
194 {
195 log<level::ERR>(
196 fmt::format("No rails found in configuration file: {}",
197 pathName.string())
198 .c_str());
199 }
200 log<level::DEBUG>(fmt::format("Found rails: {}", rails).c_str());
201
Jim Wrightd8fc0682022-01-11 15:36:00 -0600202 // List of line offsets for libgpiod
203 std::vector<unsigned int> offsets;
204
Jim Wrightd8a86172021-12-08 11:38:26 -0600205 // Parse pin information from config file
206 auto pinsIterator = rootElement.find("pins");
207 if (pinsIterator != rootElement.end())
208 {
209 for (const auto& pinElement : *pinsIterator)
210 {
211 auto nameIterator = pinElement.find("name");
212 auto lineIterator = pinElement.find("line");
213
214 if (nameIterator != pinElement.end() &&
215 lineIterator != pinElement.end())
216 {
217 std::string name = (*nameIterator).get<std::string>();
Jim Wrightd8fc0682022-01-11 15:36:00 -0600218 unsigned int line = (*lineIterator).get<unsigned int>();
Jim Wrightd8a86172021-12-08 11:38:26 -0600219
220 Pin pin;
221 pin.name = name;
222 pin.line = line;
223 pins.emplace_back(std::move(pin));
Jim Wrightd8fc0682022-01-11 15:36:00 -0600224 offsets.emplace_back(line);
Jim Wrightd8a86172021-12-08 11:38:26 -0600225 }
226 else
227 {
228 log<level::ERR>(
229 fmt::format(
230 "No name or line found within pin in configuration file: {}",
231 pathName.string())
232 .c_str());
233 }
234 }
235 }
236 else
237 {
238 log<level::ERR>(
239 fmt::format("No pins found in configuration file: {}",
240 pathName.string())
241 .c_str());
242 }
243 log<level::DEBUG>(
244 fmt::format("Found number of pins: {}", rails.size()).c_str());
Jim Wrightd8fc0682022-01-11 15:36:00 -0600245 setUpGpio(offsets);
Jim Wrightd8a86172021-12-08 11:38:26 -0600246 }
247 catch (const std::exception& e)
248 {
249 // Log error message in journal
250 log<level::ERR>(std::string("Exception parsing configuration file: " +
251 std::string(e.what()))
252 .c_str());
253 }
254}
255
Jim Wrightd8fc0682022-01-11 15:36:00 -0600256void UCD90320Monitor::setUpGpio(const std::vector<unsigned int>& offsets)
257{
258 gpiod::chip chip{"ucd90320", gpiod::chip::OPEN_BY_LABEL};
259 lines = chip.get_lines(offsets);
260 lines.request(
261 {"phosphor-power-control", gpiod::line_request::DIRECTION_INPUT, 0});
262}
263
Jim Wright7945dd22021-04-06 16:55:15 -0500264} // namespace phosphor::power::sequencer