Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

samples: Add userspace example for TI TPS6594 PFSM

This patch adds an example showing how to use PFSM devices
from a userspace application. The PMIC is armed to be triggered
by a RTC alarm to execute state transition.

Signed-off-by: Julien Panis <jpanis@baylibre.com>
Message-ID: <20230511095126.105104-7-jpanis@baylibre.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Julien Panis and committed by
Greg Kroah-Hartman
9e66fb52 dce54888

+138
+6
samples/Kconfig
··· 253 253 help 254 254 Build a sample program to work with mei device. 255 255 256 + config SAMPLE_TPS6594_PFSM 257 + bool "Build example program working with TPS6594 PFSM driver" 258 + depends on HEADERS_INSTALL 259 + help 260 + Build a sample program to work with PFSM devices. 261 + 256 262 config SAMPLE_WATCHDOG 257 263 bool "watchdog sample" 258 264 depends on CC_CAN_LINK
+1
samples/Makefile
··· 31 31 obj-y += vfio-mdev/ 32 32 subdir-$(CONFIG_SAMPLE_VFS) += vfs 33 33 obj-$(CONFIG_SAMPLE_INTEL_MEI) += mei/ 34 + obj-$(CONFIG_SAMPLE_TPS6594_PFSM) += pfsm/ 34 35 subdir-$(CONFIG_SAMPLE_WATCHDOG) += watchdog 35 36 subdir-$(CONFIG_SAMPLE_WATCH_QUEUE) += watch_queue 36 37 obj-$(CONFIG_SAMPLE_KMEMLEAK) += kmemleak/
+2
samples/pfsm/.gitignore
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + /pfsm-wakeup
+4
samples/pfsm/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + userprogs-always-y += pfsm-wakeup 3 + 4 + userccflags += -I usr/include
+125
samples/pfsm/pfsm-wakeup.c
··· 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 + }