blob: 4983fb73f50fc5eefa63322edf9bcc94acde0741 [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
18#include <fcntl.h>
19#include <linux/aspeed-lpc-sio.h>
20#include <unistd.h>
21#include <phosphor-logging/elog-errors.hpp>
22#include <xyz/openbmc_project/Chassis/Common/error.hpp>
23#include <xyz/openbmc_project/Chassis/Control/Power/server.hpp>
24#include <xyz/openbmc_project/Common/error.hpp>
25#include "gpio.hpp"
26
27static constexpr size_t POLLING_INTERVAL_MS = 500;
28
29const static constexpr char* LPC_SIO_DEVPATH = "/dev/lpc-sio";
30const static constexpr char* PGOOD_PIN = "PGOOD";
31const static constexpr char* POWER_UP_PIN = "POWER_UP_PIN";
32
33const static constexpr size_t PCH_DEVICE_BUS_ADDRESS = 3;
34const static constexpr size_t PCH_DEVICE_SLAVE_ADDRESS = 0x44;
35const static constexpr size_t PCH_CMD_REGISTER = 0;
36const static constexpr size_t PCH_POWER_DOWN_CMD = 0x02;
37
38const static constexpr size_t POWER_UP_PIN_PULSE_TIME_MS = 200;
39
40using pwr_control =
41 sdbusplus::xyz::openbmc_project::Chassis::Control::server::Power;
42
43struct PowerControl : sdbusplus::server::object_t<pwr_control>
44{
45 PowerControl(sdbusplus::bus::bus& bus, const char* path,
46 phosphor::watchdog::EventPtr event,
47 sd_event_io_handler_t handler = PowerControl::EventHandler) :
48 sdbusplus::server::object_t<pwr_control>(bus, path),
49 bus(bus), callbackHandler(handler)
50 {
51 int ret = -1;
52 char buf = '0';
53
54 // config gpio
55 ret = configGpio(PGOOD_PIN, &pgood_fd, bus);
56 if (ret < 0)
57 {
58 throw std::runtime_error("failed to config PGOOD_PIN");
59 }
60
61 ret = configGpio(POWER_UP_PIN, &power_up_fd, bus);
62 if (ret < 0)
63 {
64 closeGpio(pgood_fd);
65 throw std::runtime_error("failed to config POWER_UP_PIN");
66 }
67
68 ret = sd_event_add_io(event.get(), nullptr, pgood_fd, EPOLLPRI,
69 callbackHandler, this);
70 if (ret < 0)
71 {
72 closeGpio(pgood_fd);
73 closeGpio(power_up_fd);
74 throw std::runtime_error("failed to add to event loop");
75 }
76
77 timer.start(std::chrono::duration_cast<std::chrono::microseconds>(
78 std::chrono::milliseconds(POLLING_INTERVAL_MS)));
79 timer.setEnabled<std::true_type>();
80 phosphor::logging::log<phosphor::logging::level::DEBUG>("Enable timer");
81 }
82
83 ~PowerControl()
84 {
85 closeGpio(pgood_fd);
86 closeGpio(power_up_fd);
87 }
88
89 static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
90 void* userdata)
91 {
92 // For the first event, only set the initial status, do not emit signal
93 // since is it not triggered by the real gpio change
94 static bool first_event = true;
95 int n = -1;
96 char buf = '0';
97
98 if (!userdata)
99 {
100 phosphor::logging::log<phosphor::logging::level::ERR>(
101 "userdata null!");
102 return -1;
103 }
104
105 PowerControl* powercontrol = static_cast<PowerControl*>(userdata);
106
107 if (!powercontrol)
108 {
109 phosphor::logging::log<phosphor::logging::level::ERR>(
110 "null pointer!");
111 return -1;
112 }
113
114 n = ::lseek(fd, 0, SEEK_SET);
115 if (n < 0)
116 {
117 phosphor::logging::log<phosphor::logging::level::ERR>(
118 "lseek error!");
119 return n;
120 }
121
122 n = ::read(fd, &buf, sizeof(buf));
123 if (n < 0)
124 {
125 phosphor::logging::log<phosphor::logging::level::ERR>(
126 "read error!");
127 return n;
128 }
129
130 if (buf == '0')
131 {
132 powercontrol->state(0);
133 powercontrol->pgood(0);
134
135 if (first_event)
136 {
137 first_event = false;
138 }
139 else
140 {
141 powercontrol->powerLost();
142 }
143 }
144 else
145 {
146 powercontrol->state(1);
147 powercontrol->pgood(1);
148 if (first_event)
149 {
150 first_event = false;
151 }
152 else
153 {
154 powercontrol->powerGood();
155 }
156 }
157
158 return 0;
159 }
160
161 int32_t setPowerState(int32_t newState) override;
162 int32_t getPowerState() override;
163
164 private:
165 int power_up_fd;
166 int pgood_fd;
167 sdbusplus::bus::bus& bus;
168 sd_event_io_handler_t callbackHandler;
169};