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