From 1e563e2b731d928942f43e1341c8c50b0faf1c01 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Fri, 31 May 2024 11:39:31 +0800
Subject: [PATCH]  APPS:IGKBoard-IMX6ULL: Add test-apps source code:

---
 drivers/test-apps/pwm.c |  341 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 341 insertions(+), 0 deletions(-)

diff --git a/drivers/test-apps/pwm.c b/drivers/test-apps/pwm.c
new file mode 100644
index 0000000..c855da6
--- /dev/null
+++ b/drivers/test-apps/pwm.c
@@ -0,0 +1,341 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2021 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  pwm.c
+ *    Description:  This file is used to control PWM buzzer/Led
+ *
+ * Pin connection:
+ *               PWM Module              IGKBoard
+ *                  VCC       <----->      5V
+ *                  Led       <----->      #Pin28(PWM8)
+ *                  GND       <----->      GND
+ *
+ *
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+#include <libgen.h>
+
+#define PWM_SYS_PATH      "/sys/class/pwm/pwmchip0"
+
+#define ENABLE            1
+#define DISABLE           0
+
+
+typedef struct pwm_s 
+{
+	char				pwm_path[64]; /* PWM path, such as /sys/class/pwm/pwmchip0 */
+	char				chn_path[64]; /* channel path, such as /sys/class/pwm/pwmchip0/pwm0 */
+	int                 pwm_num;      /* pwm number */
+	int                 chn_num;      /* channel number */
+} pwm_t; 
+
+
+int init_pwm(pwm_t *pwm, int pwm_num, int chn_num);
+int conf_pwm(pwm_t *pwm, int freq, int duty);
+int turn_pwm(pwm_t *pwm, int status);
+int term_pwm(pwm_t *pwm);
+
+static inline void msleep(unsigned long ms);
+
+static inline void banner(const char *progname)
+{
+    printf("%s program Version v1.0.0\n", progname);
+    printf("Copyright (C) 2023 LingYun IoT System Studio.\n");
+}
+
+static void program_usage(const char *progname)
+{
+
+    printf("Usage: %s [OPTION]...\n", progname);
+    printf(" This is pwm control program. \n");
+
+    printf(" -p[pwm     ]  Specify PWM chip, such as 1 for pwmchip1\n");
+    printf(" -c[channel ]  Specify PWM channel, such as 0\n");
+    printf(" -f[freq    ]  Specify PWM frequency, default 2500(Hz)\n");
+    printf(" -d[duty    ]  Specify PWM duty, default 50(50%%)\n");
+    printf(" -s[status  ]  Specify PWM status: 1->on(default), 0->off\n");
+    printf(" -h[help    ]  Display this help information\n");
+    printf(" -v[version ]  Display the program version\n");
+    printf("\n");
+
+	printf("Example buzzer : %s -p 1 -c 0 -f 10000 -d 50 -s 1\n", progname);
+	printf("Example Led    : %s -p 1 -c 1 -f 100 -d 50 -s 1\n", progname);
+	printf("Example disable: %s -p 1 -c 0 -s 0\n", progname);
+
+    printf("\n");
+    banner(progname);
+    return;
+}
+
+int main(int argc, char **argv)
+{
+    int             rv;
+    char           *progname=NULL;
+    int             chn_num = -1;
+    int             pwm_num = -1;
+    int             freq = 2500;
+    int             duty = 50;
+    int             status = ENABLE;
+	pwm_t           pwm;
+
+    struct option long_options[] = {
+        {"pwm", required_argument, NULL, 'p'},
+        {"channel", required_argument, NULL, 'c'},
+        {"freq", required_argument, NULL, 'f'},
+        {"duty", required_argument, NULL, 'd'},
+        {"status", required_argument, NULL, 's'},
+        {"version", no_argument, NULL, 'v'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0}
+    };
+
+    progname = basename(argv[0]);
+
+    /* Parser the command line parameters */
+    while ((rv = getopt_long(argc, argv, "p:c:f:d:s:vh", long_options, NULL)) != -1)
+    {
+        switch (rv)
+        {
+            case 'p': /*  Set pwm chip, such as 1 for pwmchip1 */
+                pwm_num = atoi(optarg);
+                break;
+
+            case 'c': /*  Set pwm channel, such as 0,1 */
+                chn_num = atoi(optarg);
+                break;
+
+            case 'f': /*  Set pwm frequency */
+                freq = atoi(optarg);
+                break;
+
+            case 'd': /*  Set pwm duty cycle */
+                duty = atoi(optarg);
+                break;
+
+            case 's': /*  Set pwm status, 0 for disable and 1 for enable */
+                status = atoi(optarg);
+                break;
+
+            case 'v':  /* Get software version */
+                banner(progname);
+                return EXIT_SUCCESS;
+
+            case 'h':  /* Get help information */
+                program_usage(progname);
+                return 0;
+
+            default:
+                break;
+        }
+    }
+
+	if( pwm_num<0 || chn_num<0 )
+	{
+		program_usage(progname);
+		return 0;
+	}
+
+	init_pwm(&pwm, pwm_num, chn_num);
+
+
+	if( status )
+	{
+		if( (rv=conf_pwm(&pwm, freq, duty)) < 0 )
+		{
+			printf("Configure PWM failure, rv=%d\n", rv);
+			return 1;
+		}
+
+		turn_pwm(&pwm, ENABLE);
+	}
+	else
+	{
+		term_pwm(&pwm);
+	}
+
+    return 0;
+}
+
+int init_pwm(pwm_t *pwm, int pwm_num, int chn_num)
+{
+	if( !pwm || pwm_num<0 || chn_num<0 )
+	{
+		printf("Invalid input arguments\n");
+		return -1;
+	}
+
+	snprintf(pwm->pwm_path, sizeof(pwm->pwm_path), "/sys/class/pwm/pwmchip%d", pwm_num);
+	snprintf(pwm->chn_path, sizeof(pwm->chn_path), "/sys/class/pwm/pwmchip%d/pwm%d", pwm_num, chn_num);
+	pwm->pwm_num = pwm_num;
+	pwm->chn_num = chn_num;
+
+	return 0;
+}
+
+/* check PWM $channel export or not */
+int check_pwm(pwm_t *pwm)
+{
+	/* check /sys/class/pwm/pwmchipX/pwmY exist or not */
+	return access(pwm->chn_path, F_OK) ? 0 : 1;
+}
+
+/* export($export=1)/unexport($export=0) PWM $channel */
+int export_pwm(pwm_t *pwm, int export)
+{
+	int           fd;
+	char          buf[32];
+	char          path[256];
+
+	if( export && check_pwm(pwm) )
+		return 0; /* export already when export  */
+	else if( !export && !check_pwm(pwm) )
+		return 0; /* unexport already when unexport  */
+
+	/* export PWM channel by echo Y > /sys/class/pwm/pwmchipX/export */
+	snprintf(path, sizeof(path), "%s/%s", pwm->pwm_path, export?"export":"unexport");
+	if( (fd=open(path, O_WRONLY)) < 0 )
+	{
+		printf("open '%s' failed: %s\n", path, strerror(errno));
+		return -3;
+	}
+
+	snprintf(buf, sizeof(buf), "%d", pwm->chn_num);
+	write(fd, buf, strlen(buf));
+
+	msleep(100);
+
+	if( export && check_pwm(pwm) )
+		return 0; /* export already when export  */
+	else if( !export && !check_pwm(pwm) )
+		return 0; /* unexport already when unexport  */
+
+	return -4;
+}
+
+/* set PWM $channel */
+int set_pwm(pwm_t *pwm, int freq, int duty) 
+{
+	int           fd;
+	char          buf[32];
+	char          path[256];
+	int           period;
+	int           duty_cycle;
+
+	if( !check_pwm(pwm) )
+		return -2;
+
+	/* open PWM period file and write period in ns */
+	snprintf(path, sizeof(path), "%s/period", pwm->chn_path);
+	if( (fd=open(path, O_WRONLY)) < 0 )
+	{
+		printf("open '%s' failed: %s\n", path, strerror(errno));
+		return -3;
+	}
+	period = 1000000000/freq;
+	snprintf(buf, sizeof(buf), "%d", period);
+	write(fd, buf, strlen(buf));
+
+	/* open PWM duty_cycle file and write duty */
+	snprintf(path, sizeof(path), "%s/duty_cycle", pwm->chn_path);
+	if( (fd=open(path, O_WRONLY)) < 0 )
+	{
+		printf("open '%s' failed: %s\n", path, strerror(errno));
+		return -3;
+	}
+	duty_cycle = (period*duty) / 100;
+	snprintf(buf, sizeof(buf), "%d", duty_cycle);
+	write(fd, buf, strlen(buf));
+
+	return 0;
+}
+
+int conf_pwm(pwm_t *pwm, int freq, int duty)
+{
+	int           rv;
+	char          buf[32];
+	char          path[256];
+
+	if( (rv=export_pwm(pwm, 1)) )
+	{
+		printf("export PWM channel[%d] failed, rv=%d\n", pwm->chn_num, rv);
+		return rv; 
+	}
+
+	if( (rv=set_pwm(pwm, freq, duty)) )
+	{
+		printf("config PWM channel[%d] failed, rv=%d\n", pwm->chn_num, rv);
+		return rv;
+	}
+
+	printf("config pwm%d channel%d with freq[%d] duty[%d] okay\n", pwm->pwm_num, pwm->chn_num, freq, duty);
+
+	return 0;
+}
+
+int turn_pwm(pwm_t *pwm, int status)
+{
+	int           fd;
+	char          buf[32];
+	char          path[256];
+
+	if( !check_pwm(pwm) )
+		return -1;
+
+	/* open PWM enable file and enable(1)/disable(0) it */
+	snprintf(path, sizeof(path), "%s/enable", pwm->chn_path);
+	if( (fd=open(path, O_WRONLY)) < 0 )
+	{
+		printf("open '%s' failed: %s\n", path, strerror(errno));
+		return -3;
+	}
+	snprintf(buf, sizeof(buf), "%d", status?1:0);
+	write(fd, buf, strlen(buf));
+
+	printf("pwm[%d] channel[%d]%s\n", pwm->pwm_num, pwm->chn_num, status?"enable":"disable");
+
+	return 0;
+}
+
+int term_pwm(pwm_t *pwm)
+{
+	if( !check_pwm(pwm) )
+		return 0;
+
+	turn_pwm(pwm, DISABLE);
+	export_pwm(pwm, 0);
+
+	return 0;
+}
+
+static inline void msleep(unsigned long ms)
+{
+    struct timespec cSleep;
+    unsigned long ulTmp;
+
+    cSleep.tv_sec = ms / 1000;
+    if (cSleep.tv_sec == 0)
+    {
+        ulTmp = ms * 10000;
+        cSleep.tv_nsec = ulTmp * 100;
+    }
+    else
+    {
+        cSleep.tv_nsec = 0;
+    }
+
+    nanosleep(&cSleep, 0);
+
+    return ;
+}

--
Gitblit v1.9.1