1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * TPS6594 PFSM userspace example 4 * 5 * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ 6 * 7 * This example shows how to use PFSMs from a userspace application, 8 * on TI j721s2 platform. The PMIC is armed to be triggered by a RTC 9 * alarm to execute state transition (RETENTION to ACTIVE). 10 */ 11 12 #include <fcntl.h> 13 #include <stdio.h> 14 #include <sys/ioctl.h> 15 #include <unistd.h> 16 17 #include <linux/rtc.h> 18 #include <linux/tps6594_pfsm.h> 19 20 #define ALARM_DELTA_SEC 30 21 22 #define RTC_A "/dev/rtc0" 23 24 #define PMIC_NB 3 25 #define PMIC_A "/dev/pfsm-0-0x48" 26 #define PMIC_B "/dev/pfsm-0-0x4c" 27 #define PMIC_C "/dev/pfsm-2-0x58" 28 29 static const char * const dev_pfsm[] = {PMIC_A, PMIC_B, PMIC_C}; 30 31 int main(int argc, char *argv[]) 32 { 33 int i, ret, fd_rtc, fd_pfsm[PMIC_NB] = { 0 }; 34 struct rtc_time rtc_tm; 35 struct pmic_state_opt pmic_opt = { 0 }; 36 unsigned long data; 37 38 fd_rtc = open(RTC_A, O_RDONLY); 39 if (fd_rtc < 0) { 40 perror("Failed to open RTC device."); 41 goto out; 42 } 43 44 for (i = 0 ; i < PMIC_NB ; i++) { 45 fd_pfsm[i] = open(dev_pfsm[i], O_RDWR); 46 if (fd_pfsm[i] < 0) { 47 perror("Failed to open PFSM device."); 48 goto out; 49 } 50 } 51 52 /* Read RTC date/time */ 53 ret = ioctl(fd_rtc, RTC_RD_TIME, &rtc_tm); 54 if (ret < 0) { 55 perror("Failed to read RTC date/time."); 56 goto out; 57 } 58 printf("Current RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", 59 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, 60 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); 61 62 /* Set RTC alarm to ALARM_DELTA_SEC sec in the future, and check for rollover */ 63 rtc_tm.tm_sec += ALARM_DELTA_SEC; 64 if (rtc_tm.tm_sec >= 60) { 65 rtc_tm.tm_sec %= 60; 66 rtc_tm.tm_min++; 67 } 68 if (rtc_tm.tm_min == 60) { 69 rtc_tm.tm_min = 0; 70 rtc_tm.tm_hour++; 71 } 72 if (rtc_tm.tm_hour == 24) 73 rtc_tm.tm_hour = 0; 74 ret = ioctl(fd_rtc, RTC_ALM_SET, &rtc_tm); 75 if (ret < 0) { 76 perror("Failed to set RTC alarm."); 77 goto out; 78 } 79 80 /* Enable alarm interrupts */ 81 ret = ioctl(fd_rtc, RTC_AIE_ON, 0); 82 if (ret < 0) { 83 perror("Failed to enable alarm interrupts."); 84 goto out; 85 } 86 printf("Waiting %d seconds for alarm...\n", ALARM_DELTA_SEC); 87 88 /* 89 * Set RETENTION state with options for PMIC_C/B/A respectively. 90 * Since PMIC_A is master, it should be the last one to be configured. 91 */ 92 pmic_opt.ddr_retention = 1; 93 for (i = PMIC_NB - 1 ; i >= 0 ; i--) { 94 printf("Set RETENTION state for PMIC_%d.\n", i); 95 sleep(1); 96 ret = ioctl(fd_pfsm[i], PMIC_SET_RETENTION_STATE, &pmic_opt); 97 if (ret < 0) { 98 perror("Failed to set RETENTION state."); 99 goto out_reset; 100 } 101 } 102 103 /* This blocks until the alarm ring causes an interrupt */ 104 ret = read(fd_rtc, &data, sizeof(unsigned long)); 105 if (ret < 0) 106 perror("Failed to get RTC alarm."); 107 else 108 puts("Alarm rang.\n"); 109 110 out_reset: 111 ioctl(fd_rtc, RTC_AIE_OFF, 0); 112 113 /* Set ACTIVE state for PMIC_A */ 114 ioctl(fd_pfsm[0], PMIC_SET_ACTIVE_STATE, 0); 115 116 out: 117 for (i = 0 ; i < PMIC_NB ; i++) 118 if (fd_pfsm[i]) 119 close(fd_pfsm[i]); 120 121 if (fd_rtc) 122 close(fd_rtc); 123 124 return 0; 125 } 126