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