blob: f68b71d2a541ccaf51d660db21128e779d8c8f22 [file] [log] [blame]
Kuiying Wang64ff7ce2018-08-15 11:17:06 +08001/*
2// Copyright (c) 2018 Intel 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
17#pragma once
Patrick Venture8fbed2e2018-11-01 19:25:31 -070018#include "gpio.hpp"
19
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080020#include <fcntl.h>
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080021#include <unistd.h>
Patrick Venture8fbed2e2018-11-01 19:25:31 -070022
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080023#include <phosphor-logging/elog-errors.hpp>
24#include <xyz/openbmc_project/Chassis/Common/error.hpp>
25#include <xyz/openbmc_project/Chassis/Control/Power/server.hpp>
26#include <xyz/openbmc_project/Common/error.hpp>
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080027
James Feist676d2c32019-02-14 10:07:27 -080028// static constexpr size_t POLLING_INTERVAL_MS = 500;
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080029
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080030const static constexpr char* PGOOD_PIN = "PGOOD";
31const static constexpr char* POWER_UP_PIN = "POWER_UP_PIN";
32
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080033const static constexpr size_t POWER_UP_PIN_PULSE_TIME_MS = 200;
34
Kuiying Wang80f6d922018-11-13 16:34:07 +080035struct EventDeleter
36{
James Feist676d2c32019-02-14 10:07:27 -080037 void operator()(sd_event* event) const
Kuiying Wang80f6d922018-11-13 16:34:07 +080038 {
39 event = sd_event_unref(event);
40 }
41};
42
43using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
44
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080045using pwr_control =
46 sdbusplus::xyz::openbmc_project::Chassis::Control::server::Power;
47
48struct PowerControl : sdbusplus::server::object_t<pwr_control>
49{
James Feist676d2c32019-02-14 10:07:27 -080050 PowerControl(sdbusplus::bus::bus& bus, const char* path, EventPtr& event,
51 // phosphor::watchdog::EventPtr event,
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080052 sd_event_io_handler_t handler = PowerControl::EventHandler) :
53 sdbusplus::server::object_t<pwr_control>(bus, path),
54 bus(bus), callbackHandler(handler)
55 {
56 int ret = -1;
57 char buf = '0';
58
59 // config gpio
60 ret = configGpio(PGOOD_PIN, &pgood_fd, bus);
61 if (ret < 0)
62 {
63 throw std::runtime_error("failed to config PGOOD_PIN");
64 }
65
66 ret = configGpio(POWER_UP_PIN, &power_up_fd, bus);
67 if (ret < 0)
68 {
69 closeGpio(pgood_fd);
70 throw std::runtime_error("failed to config POWER_UP_PIN");
71 }
James Feist676d2c32019-02-14 10:07:27 -080072 /*
73 ret = sd_event_add_io(event.get(), nullptr, pgood_fd, EPOLLPRI,
74 callbackHandler, this);
75 if (ret < 0)
76 {
77 closeGpio(pgood_fd);
78 closeGpio(power_up_fd);
79 throw std::runtime_error("failed to add to event loop");
80 }
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080081
James Feist676d2c32019-02-14 10:07:27 -080082 timer.start(std::chrono::duration_cast<std::chrono::microseconds>(
83 std::chrono::milliseconds(POLLING_INTERVAL_MS)));
84 timer.setEnabled<std::true_type>();
85 phosphor::logging::log<phosphor::logging::level::DEBUG>("Enable
86 timer");
87 */
Kuiying Wang64ff7ce2018-08-15 11:17:06 +080088 }
89
90 ~PowerControl()
91 {
92 closeGpio(pgood_fd);
93 closeGpio(power_up_fd);
94 }
95
96 static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
97 void* userdata)
98 {
99 // For the first event, only set the initial status, do not emit signal
100 // since is it not triggered by the real gpio change
101 static bool first_event = true;
102 int n = -1;
103 char buf = '0';
104
105 if (!userdata)
106 {
107 phosphor::logging::log<phosphor::logging::level::ERR>(
108 "userdata null!");
109 return -1;
110 }
111
112 PowerControl* powercontrol = static_cast<PowerControl*>(userdata);
113
114 if (!powercontrol)
115 {
116 phosphor::logging::log<phosphor::logging::level::ERR>(
117 "null pointer!");
118 return -1;
119 }
120
121 n = ::lseek(fd, 0, SEEK_SET);
122 if (n < 0)
123 {
124 phosphor::logging::log<phosphor::logging::level::ERR>(
125 "lseek error!");
126 return n;
127 }
128
129 n = ::read(fd, &buf, sizeof(buf));
130 if (n < 0)
131 {
132 phosphor::logging::log<phosphor::logging::level::ERR>(
133 "read error!");
134 return n;
135 }
136
137 if (buf == '0')
138 {
139 powercontrol->state(0);
Kuiying Wang80f6d922018-11-13 16:34:07 +0800140 powercontrol->pGood(0);
Kuiying Wang64ff7ce2018-08-15 11:17:06 +0800141
142 if (first_event)
143 {
144 first_event = false;
145 }
146 else
147 {
James Feist676d2c32019-02-14 10:07:27 -0800148 // powercontrol->powerLost();
Kuiying Wang64ff7ce2018-08-15 11:17:06 +0800149 }
150 }
151 else
152 {
153 powercontrol->state(1);
Kuiying Wang80f6d922018-11-13 16:34:07 +0800154 powercontrol->pGood(1);
Kuiying Wang64ff7ce2018-08-15 11:17:06 +0800155 if (first_event)
156 {
157 first_event = false;
158 }
159 else
160 {
James Feist676d2c32019-02-14 10:07:27 -0800161 // powercontrol->powerGood();
Kuiying Wang64ff7ce2018-08-15 11:17:06 +0800162 }
163 }
164
165 return 0;
166 }
167
James Feist676d2c32019-02-14 10:07:27 -0800168 bool forcePowerOff() override;
169 // todo: when dbus interfaces is fixed, these should be override
170 int32_t setPowerState(int32_t newState); // override;
171 int32_t getPowerState(); // override;
Kuiying Wang64ff7ce2018-08-15 11:17:06 +0800172
173 private:
174 int power_up_fd;
175 int pgood_fd;
176 sdbusplus::bus::bus& bus;
177 sd_event_io_handler_t callbackHandler;
178};