1 /* USRP E310 TP54478 driver
2  * Copyright (C) 2014 Ettus Research
3  * This file is part of the USRP E310 Firmware
4  * The USRP E310 Firmware is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  * The USRP E310 Firmware is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License
13  * along with the USRP E310 Firmware. If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 #include "mcu_settings.h"
17 #include "io.h"
18 #include "tps54478.h"
19 
20 #include <stdlib.h>
21 
22 #include <util/delay.h>
23 #include <util/atomic.h>
24 
25 static io_pin_t CORE_PWR_EN = IO_PA(3);
26 static io_pin_t CORE_PGOOD = IO_PB(0);
27 
28 /* per spec we should wait 3 ms here,
29  * but 10 is better to give external PSU some time
30  * to settle down*/
31 static const uint8_t TPS54478_START_DELAY = 10;
32 
33 /* we'll use this to check for events in the event handler */
34 static volatile bool tps54478_event = false;
35 
tps54478_get_power_good(void)36 bool tps54478_get_power_good(void)
37 {
38 	return io_test_pin(CORE_PGOOD);
39 }
40 
tps54478_set_regulator(pmu_regulator_t * pmu_reg,bool on)41 static int8_t tps54478_set_regulator(pmu_regulator_t *pmu_reg, bool on)
42 {
43 	(void) pmu_reg;
44 
45 	if (on) {
46 		io_input_pin(CORE_PWR_EN);
47 		_delay_ms(TPS54478_START_DELAY);
48 	} else {
49 		io_output_pin(CORE_PWR_EN);
50 		/* no delay here as we can't detect this state anyway */
51 		return 0;
52 	}
53 	/* return zero on success ... */
54 	return !(on == tps54478_get_power_good());
55 }
56 
tps54478_init(bool enable)57 void tps54478_init(bool enable)
58 {
59 	/* enable pull-up for open drain */
60 	io_input_pin(CORE_PGOOD);
61 	io_set_pin(CORE_PGOOD);
62 
63 	tps54478_set_regulator(NULL, enable);
64 
65 	io_clear_pin(CORE_PWR_EN);
66 }
67 
tps54478_check_events(pmu_regulator_t * reg)68 int8_t tps54478_check_events(pmu_regulator_t *reg)
69 {
70 	bool power_good;
71 	bool event;
72 
73 	event = false;
74 	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
75 		if (tps54478_event) {
76 			tps54478_event = false;
77 			event = true;
78 		}
79 	}
80 
81 	if (event) {
82 		power_good = tps54478_get_power_good();
83 		if (!power_good)
84 			return -1;
85 	}
86 	return 0;
87 }
88 
89 const pmu_regulator_ops_t tps54478_ops = {
90 	.set_voltage = NULL,
91 	.set_regulator = tps54478_set_regulator,
92 	.check_events	= tps54478_check_events,
93 };
94 
tps54478_irq_handler(void)95 irqreturn_t tps54478_irq_handler(void)
96 {
97 	bool power_good;
98 	power_good = tps54478_get_power_good();
99 
100 	/* check if the device indicates power is good,
101 	 * if it is probably we're not the source of the IRQ,
102 	 * if it is *not* set the event flag to deal with it later */
103 	if (power_good) {
104 		return IRQ_NONE;
105 	} else {
106 		tps54478_event = true;
107 		return IRQ_HANDLED;
108 	}
109 	return IRQ_HANDLED;
110 }
111