From dffd9696989dd020e44e69f668eec63aa2fe1b6e Mon Sep 17 00:00:00 2001 From: Nandkumar Joshi Date: Fri, 13 Mar 2020 01:12:43 +0530 Subject: [PATCH 1/2] Add support for Sifive PWM --- Makefile.am | 4 + Makefile.in | 52 +++--- aclocal.m4 | 50 +++--- metal/drivers/sifive_pwm0.h | 27 +++ metal/pwm.h | 160 +++++++++++++++++ src/drivers/sifive_pwm0.c | 338 ++++++++++++++++++++++++++++++++++++ src/pwm.c | 36 ++++ 7 files changed, 620 insertions(+), 47 deletions(-) create mode 100644 metal/drivers/sifive_pwm0.h create mode 100644 metal/pwm.h create mode 100644 src/drivers/sifive_pwm0.c create mode 100644 src/pwm.c diff --git a/Makefile.am b/Makefile.am index 0cdfd0bd..acb944a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,7 @@ nobase_include_HEADERS += \ metal/drivers/sifive_gpio0.h \ metal/drivers/sifive_i2c0.h \ metal/drivers/sifive_local-external-interrupts0.h \ + metal/drivers/sifive_pwm0.h \ metal/drivers/sifive_rtc0.h \ metal/drivers/sifive_spi0.h \ metal/drivers/sifive_test0.h \ @@ -78,6 +79,7 @@ nobase_include_HEADERS += \ metal/memory.h \ metal/pmp.h \ metal/privilege.h \ + metal/pwm.h\ metal/rtc.h \ metal/shutdown.h \ metal/spi.h \ @@ -116,6 +118,7 @@ libmetal_a_SOURCES = \ src/drivers/sifive_gpio0.c \ src/drivers/sifive_i2c0.c \ src/drivers/sifive_local-external-interrupts0.c \ + src/drivers/sifive_pwm0.c \ src/drivers/sifive_rtc0.c \ src/drivers/sifive_spi0.c \ src/drivers/sifive_test0.c \ @@ -139,6 +142,7 @@ libmetal_a_SOURCES = \ src/memory.c \ src/pmp.c \ src/privilege.c \ + src/pwm.c\ src/rtc.c \ src/shutdown.c \ src/spi.c \ diff --git a/Makefile.in b/Makefile.in index d5ab645a..4e38c146 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. +# Makefile.in generated by automake 1.15.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2014 Free Software Foundation, Inc. +# Copyright (C) 1994-2017 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -224,6 +224,7 @@ am_libmetal_a_OBJECTS = src/drivers/fixed-clock.$(OBJEXT) \ src/drivers/sifive_gpio0.$(OBJEXT) \ src/drivers/sifive_i2c0.$(OBJEXT) \ src/drivers/sifive_local-external-interrupts0.$(OBJEXT) \ + src/drivers/sifive_pwm0.$(OBJEXT) \ src/drivers/sifive_rtc0.$(OBJEXT) \ src/drivers/sifive_spi0.$(OBJEXT) \ src/drivers/sifive_test0.$(OBJEXT) \ @@ -236,11 +237,11 @@ am_libmetal_a_OBJECTS = src/drivers/fixed-clock.$(OBJEXT) \ src/gpio.$(OBJEXT) src/i2c.$(OBJEXT) src/init.$(OBJEXT) \ src/interrupt.$(OBJEXT) src/led.$(OBJEXT) src/lock.$(OBJEXT) \ src/memory.$(OBJEXT) src/pmp.$(OBJEXT) src/privilege.$(OBJEXT) \ - src/rtc.$(OBJEXT) src/shutdown.$(OBJEXT) src/spi.$(OBJEXT) \ - src/switch.$(OBJEXT) src/synchronize_harts.$(OBJEXT) \ - src/timer.$(OBJEXT) src/time.$(OBJEXT) src/trap.$(OBJEXT) \ - src/tty.$(OBJEXT) src/uart.$(OBJEXT) src/vector.$(OBJEXT) \ - src/watchdog.$(OBJEXT) + src/pwm.$(OBJEXT) src/rtc.$(OBJEXT) src/shutdown.$(OBJEXT) \ + src/spi.$(OBJEXT) src/switch.$(OBJEXT) \ + src/synchronize_harts.$(OBJEXT) src/timer.$(OBJEXT) \ + src/time.$(OBJEXT) src/trap.$(OBJEXT) src/tty.$(OBJEXT) \ + src/uart.$(OBJEXT) src/vector.$(OBJEXT) src/watchdog.$(OBJEXT) libmetal_a_OBJECTS = $(am_libmetal_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -450,17 +451,17 @@ nobase_include_HEADERS = metal/machine.h metal/machine/inline.h \ metal/drivers/sifive_gpio-switches.h \ metal/drivers/sifive_gpio0.h metal/drivers/sifive_i2c0.h \ metal/drivers/sifive_local-external-interrupts0.h \ - metal/drivers/sifive_rtc0.h metal/drivers/sifive_spi0.h \ - metal/drivers/sifive_test0.h metal/drivers/sifive_trace.h \ - metal/drivers/sifive_uart0.h metal/drivers/sifive_wdog0.h \ - metal/drivers/ucb_htif0.h metal/atomic.h metal/button.h \ - metal/cache.h metal/clock.h metal/compiler.h metal/cpu.h \ - metal/csr.h metal/gpio.h metal/i2c.h metal/init.h \ - metal/interrupt.h metal/io.h metal/itim.h metal/led.h \ - metal/lock.h metal/memory.h metal/pmp.h metal/privilege.h \ - metal/rtc.h metal/shutdown.h metal/spi.h metal/switch.h \ - metal/timer.h metal/time.h metal/tty.h metal/uart.h \ - metal/watchdog.h + metal/drivers/sifive_pwm0.h metal/drivers/sifive_rtc0.h \ + metal/drivers/sifive_spi0.h metal/drivers/sifive_test0.h \ + metal/drivers/sifive_trace.h metal/drivers/sifive_uart0.h \ + metal/drivers/sifive_wdog0.h metal/drivers/ucb_htif0.h \ + metal/atomic.h metal/button.h metal/cache.h metal/clock.h \ + metal/compiler.h metal/cpu.h metal/csr.h metal/gpio.h \ + metal/i2c.h metal/init.h metal/interrupt.h metal/io.h \ + metal/itim.h metal/led.h metal/lock.h metal/memory.h \ + metal/pmp.h metal/privilege.h metal/pwm.h metal/rtc.h \ + metal/shutdown.h metal/spi.h metal/switch.h metal/timer.h \ + metal/time.h metal/tty.h metal/uart.h metal/watchdog.h # This will generate these sources before the compilation step BUILT_SOURCES = \ @@ -495,6 +496,7 @@ libmetal_a_SOURCES = \ src/drivers/sifive_gpio0.c \ src/drivers/sifive_i2c0.c \ src/drivers/sifive_local-external-interrupts0.c \ + src/drivers/sifive_pwm0.c \ src/drivers/sifive_rtc0.c \ src/drivers/sifive_spi0.c \ src/drivers/sifive_test0.c \ @@ -518,6 +520,7 @@ libmetal_a_SOURCES = \ src/memory.c \ src/pmp.c \ src/privilege.c \ + src/pwm.c\ src/rtc.c \ src/shutdown.c \ src/spi.c \ @@ -770,6 +773,8 @@ src/drivers/sifive_i2c0.$(OBJEXT): src/drivers/$(am__dirstamp) \ src/drivers/sifive_local-external-interrupts0.$(OBJEXT): \ src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) +src/drivers/sifive_pwm0.$(OBJEXT): src/drivers/$(am__dirstamp) \ + src/drivers/$(DEPDIR)/$(am__dirstamp) src/drivers/sifive_rtc0.$(OBJEXT): src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) src/drivers/sifive_spi0.$(OBJEXT): src/drivers/$(am__dirstamp) \ @@ -811,6 +816,7 @@ src/memory.$(OBJEXT): src/$(am__dirstamp) \ src/pmp.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/privilege.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) +src/pwm.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/rtc.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/shutdown.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) @@ -890,6 +896,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/pmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/privilege.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/pwm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/rtc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/shutdown.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/spi.Po@am__quote@ @@ -923,6 +930,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_gpio0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_i2c0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_local-external-interrupts0.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_pwm0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_rtc0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_spi0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_test0.Po@am__quote@ @@ -1086,7 +1094,7 @@ distdir: $(DISTFILES) ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir @@ -1112,7 +1120,7 @@ dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir @@ -1130,7 +1138,7 @@ dist dist-all: distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ @@ -1140,7 +1148,7 @@ distcheck: dist *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac diff --git a/aclocal.m4 b/aclocal.m4 index 42ec7eed..2e4e7235 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.15 -*- Autoconf -*- +# generated automatically by aclocal 1.15.1 -*- Autoconf -*- -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2017 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Copyright (C) 2002-2014 Free Software Foundation, Inc. +# Copyright (C) 2002-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.15], [], +m4_if([$1], [1.15.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,12 +51,12 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.15])dnl +[AM_AUTOMAKE_VERSION([1.15.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) -# Copyright (C) 2011-2014 Free Software Foundation, Inc. +# Copyright (C) 2011-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -118,7 +118,7 @@ AC_SUBST([AR])dnl # Figure out how to run the assembler. -*- Autoconf -*- -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -138,7 +138,7 @@ _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -190,7 +190,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# Copyright (C) 1997-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -221,7 +221,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -412,7 +412,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -488,7 +488,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -685,7 +685,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -706,7 +706,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2014 Free Software Foundation, Inc. +# Copyright (C) 2003-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -728,7 +728,7 @@ AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -763,7 +763,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -813,7 +813,7 @@ rm -f confinc confmf # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# Copyright (C) 1997-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -852,7 +852,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -881,7 +881,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -928,7 +928,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -947,7 +947,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1028,7 +1028,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2014 Free Software Foundation, Inc. +# Copyright (C) 2009-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1088,7 +1088,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1116,7 +1116,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2014 Free Software Foundation, Inc. +# Copyright (C) 2006-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1135,7 +1135,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2014 Free Software Foundation, Inc. +# Copyright (C) 2004-2017 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/metal/drivers/sifive_pwm0.h b/metal/drivers/sifive_pwm0.h new file mode 100644 index 00000000..b8efc70f --- /dev/null +++ b/metal/drivers/sifive_pwm0.h @@ -0,0 +1,27 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef METAL__DRIVERS__SIFIVE_PWM0_H +#define METAL__DRIVERS__SIFIVE_PWM0_H + +#include +#include +#include + +struct __metal_driver_vtable_sifive_pwm0 { + const struct metal_pwm_vtable pwm; +}; + +__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_pwm0) + +struct __metal_driver_sifive_pwm0 { + struct metal_pwm pwm; + unsigned int max_count; + unsigned int count_val; + unsigned int freq; + unsigned int duty[METAL_MAX_PWM0_NCMP]; + metal_clock_callback pre_rate_change_callback; + metal_clock_callback post_rate_change_callback; +}; + +#endif diff --git a/metal/pwm.h b/metal/pwm.h new file mode 100644 index 00000000..a6d37a4d --- /dev/null +++ b/metal/pwm.h @@ -0,0 +1,160 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef METAL__PWM_H +#define METAL__PWM_H + +/*! @brief Enums for PWM running modes. */ +typedef enum { + METAL_PWM_CONTINUOUS = 0, + METAL_PWM_ONE_SHOT = 1 +} metal_pwm_run_mode_t; + +/*! @brief Enums for Phase correct PWM. */ +typedef enum { + METAL_PWM_PHASE_CORRECT_DISABLE = 0, + METAL_PWM_PHASE_CORRECT_ENABLE = 1, +} metal_pwm_phase_correct_t; + +/*! @brief Enums for Interrupts enable/disable. */ +typedef enum { + METAL_PWM_INTERRUPT_DISABLE = 0, + METAL_PWM_INTERRUPT_ENABLE = 1, +} metal_pwm_interrupt_t; + +struct metal_pwm; + +/*! @brief vtable for PWM. */ +struct metal_pwm_vtable { + int (*enable)(struct metal_pwm *pwm); + int (*disable)(struct metal_pwm *pwm); + int (*set_freq)(struct metal_pwm *pwm, unsigned int idx, unsigned int freq); + int (*set_duty)(struct metal_pwm *pwm, unsigned int idx, unsigned int duty, + metal_pwm_phase_correct_t phase_corr); + unsigned int (*get_duty)(struct metal_pwm *pwm, unsigned int idx); + unsigned int (*get_freq)(struct metal_pwm *pwm, unsigned int idx); + int (*trigger)(struct metal_pwm *pwm, unsigned int idx, metal_pwm_run_mode_t mode); + int (*stop)(struct metal_pwm *pwm, unsigned int idx); + int (*cfg_interrupt)(struct metal_pwm *pwm, metal_pwm_interrupt_t flag); + int (*clr_interrupt)(struct metal_pwm *pwm, unsigned int idx); + struct metal_interrupt *(*get_interrupt_controller)(struct metal_pwm *pwm); + int (*get_interrupt_id)(struct metal_pwm *pwm, unsigned int idx); +}; + +/*! @brief A handle for a PWM device. */ +struct metal_pwm { + const struct metal_pwm_vtable *vtable; +}; + +/*! @brief Gets a PWM device handle. + * @param device_num The index of the desired PWM device. + * @return A handle to the PWM device, or NULL if the device does not exist.*/ +struct metal_pwm *metal_pwm_get_device(unsigned int device_num); + +/*! @brief Enables PWM operation. + * @param pwm The handle for the PWM device to initialize. + * @return 0 If no error.*/ +inline int metal_pwm_enable(struct metal_pwm *pwm) { + return pwm->vtable->enable(pwm); +} + +/*! @brief Disables PWM operation. + * @param pwm The handle for the PWM device to be disabled. + * @return 0 If no error.*/ +inline int metal_pwm_disable(struct metal_pwm *pwm) { + return pwm->vtable->disable(pwm); +} + +/*! @brief Sets frequency in Hz for a given PWM instance. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @param freq PWM frequency in Hz. + * @return 0 If no error.*/ +inline int metal_pwm_set_freq(struct metal_pwm *pwm, unsigned int idx, + unsigned int freq) { + return pwm->vtable->set_freq(pwm, idx, freq); +} + +/*! @brief Sets duty cycle in percent values [0 - 100] for a given PWM instance. + * Phase correct mode provides center aligned PWM waveform output. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @param duty PWM duty cycle value. + * @param phase_corr Enable / Disable phase correct mode. + * @return 0 If no error.*/ +inline int metal_pwm_set_duty(struct metal_pwm *pwm, unsigned int idx, + unsigned int duty, + metal_pwm_phase_correct_t phase_corr) { + return pwm->vtable->set_duty(pwm, idx, duty, phase_corr); +} + +/*! @brief Gets duty cycle in percent values [0 - 100] for a given PWM instance. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @return PWM duty cycle value.*/ +inline unsigned int metal_pwm_get_duty(struct metal_pwm *pwm, + unsigned int idx) { + return pwm->vtable->get_duty(pwm, idx); +} + +/*! @brief Gets frequency in Hz for a given PWM instance. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @return PWM frequency in Hz.*/ +inline unsigned int metal_pwm_get_freq(struct metal_pwm *pwm, + unsigned int idx) { + return pwm->vtable->get_freq(pwm, idx); +} + +/*! @brief Starts a PWM instance in selected run mode (continuous/one shot). + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @return 0 If no error.*/ +inline int metal_pwm_trigger(struct metal_pwm *pwm, unsigned int idx, metal_pwm_run_mode_t mode) { + return pwm->vtable->trigger(pwm, idx, mode); +} + +/*! @brief Stops a running PWM instance in continuous mode. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @return 0 If no error.*/ +inline int metal_pwm_stop(struct metal_pwm *pwm, unsigned int idx) { + return pwm->vtable->stop(pwm, idx); +} + +/*! @brief Enable or Disable PWM interrupts. + * @param pwm PWM device handle. + * @param flag PWM interrupt enable flag. + * @return 0 If no error.*/ +inline int metal_pwm_cfg_interrupt(struct metal_pwm *pwm, + metal_pwm_interrupt_t flag) { + return pwm->vtable->cfg_interrupt(pwm, flag); +} + +/*! @brief Clears pending interrupt flags. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @return 0 If no error.*/ +inline int metal_pwm_clr_interrupt(struct metal_pwm *pwm, unsigned int idx) { + return pwm->vtable->clr_interrupt(pwm, idx); +} + +/*! @brief Get the interrupt controller of the PWM peripheral. + * The interrupt controller must be initialized before any interrupts can be + * registered or enabled with it. + * @param pwm PWM device handle. + * @return The handle for the PWM interrupt controller.*/ +inline struct metal_interrupt * +metal_pwm_interrupt_controller(struct metal_pwm *pwm) { + return pwm->vtable->get_interrupt_controller(pwm); +} + +/*! @brief Get the interrupt ID of the PWM peripheral. + * @param pwm PWM device handle. + * @param idx PWM channel id. + * @return The PWM interrupt id.*/ +inline int metal_pwm_get_interrupt_id(struct metal_pwm *pwm, unsigned int idx) { + return pwm->vtable->get_interrupt_id(pwm, idx); +} + +#endif diff --git a/src/drivers/sifive_pwm0.c b/src/drivers/sifive_pwm0.c new file mode 100644 index 00000000..a602fcdc --- /dev/null +++ b/src/drivers/sifive_pwm0.c @@ -0,0 +1,338 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include + +#ifdef METAL_SIFIVE_PWM0 +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register fields */ +#define METAL_PWMCFG_STICKY (1UL << 8) +#define METAL_PWMCFG_ZEROCMP (1UL << 9) +#define METAL_PWMCFG_DEGLITCH (1UL << 10) +#define METAL_PWMCFG_ENALWAYS (1UL << 12) +#define METAL_PWMCFG_ENONESHOT (1UL << 13) +#define METAL_PWMCFG_CMPCENTER(x) (1UL << (16 + x)) +#define METAL_PWMCFG_CMPIP(x) (1UL << (28 + x)) +#define METAL_SIFIVE_PWM0_PWMCMP(x) METAL_SIFIVE_PWM0_PWMCMP0 + x * 4 + +/* Macros to access registers */ +#define METAL_PWM_REG(offset) ((base + offset)) +#define METAL_PWM_REGW(offset) \ + (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_PWM_REG(offset))) + +/* Macro to get PWM compare count */ +#define METAL_PWM_GETCMPVAL(duty) (duty * pwm->count_val) / 100U +/* Max duty cycle value */ +#define METAL_PWM_MAXDUTY 100UL +/* Max pre-scalar value */ +#define METAL_PWM_MAXPRESCAL 15UL + +/* Check endianess */ +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +#error *** Unsupported endianess *** +#endif + +/* Return values */ +#define METAL_PWM_RET_OK 0 +#define METAL_PWM_RET_ERR -1 + +#define METAL_PWM_DEBUG + +static void pre_rate_change_callback(void *priv) { + struct metal_pwm *gpwm = priv; + /* Disable active PWM instance. */ + gpwm->vtable->stop(gpwm, 0); +} + +static void post_rate_change_callback(void *priv) { + struct __metal_driver_sifive_pwm0 *pwm = priv; + struct metal_pwm *gpwm = priv; + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + unsigned int cmp_count = __metal_driver_sifive_pwm0_comparator_count(gpwm); + unsigned int idx = 0; + unsigned int duty; + + /* Check if PWM frequency was set */ + if (pwm->freq != 0) { + /* Set frequency after clock rate change */ + gpwm->vtable->set_freq(gpwm, 0, pwm->freq); + + /* Set duty cycle after clock rate change */ + while (++idx < cmp_count) { + duty = pwm->duty[idx]; + if (duty != 0) { + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCMP(idx)) = + METAL_PWM_GETCMPVAL(duty); + } + } + } +} + +static int __metal_driver_sifive_pwm0_enable(struct metal_pwm *gpwm) { + struct __metal_driver_sifive_gpio0 *pinmux = + __metal_driver_sifive_pwm0_pinmux(gpwm); + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + struct __metal_driver_sifive_pwm0 *pwm = (void *)gpwm; + int ret = METAL_PWM_RET_ERR; + + if (base != 0) { + + if ((pinmux != NULL) && (gpwm != NULL)) { + /* Configure PWM I/O pins */ + long pinmux_output_selector = + __metal_driver_sifive_pwm0_pinmux_output_selector(gpwm); + long pinmux_source_selector = + __metal_driver_sifive_pwm0_pinmux_source_selector(gpwm); + + pinmux->gpio.vtable->enable_io((struct metal_gpio *)pinmux, + pinmux_output_selector, + pinmux_source_selector); + } + + /* Initialize default values */ + pwm->max_count = + (1UL << __metal_driver_sifive_pwm0_compare_width(gpwm)) - 1; + pwm->freq = 0; + pwm->count_val = 0; + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) = 0; + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static int __metal_driver_sifive_pwm0_disable(struct metal_pwm *gpwm) { + struct __metal_driver_sifive_gpio0 *pinmux = + __metal_driver_sifive_pwm0_pinmux(gpwm); + int ret = METAL_PWM_RET_ERR; + + if (gpwm != NULL) { + + if (pinmux != NULL) { + /* Disable PWM I/O pins */ + long pinmux_source_selector = + __metal_driver_sifive_pwm0_pinmux_source_selector(gpwm); + pinmux->gpio.vtable->disable_io((struct metal_gpio *)pinmux, + pinmux_source_selector); + } + + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static int __metal_driver_sifive_pwm0_set_freq(struct metal_pwm *gpwm, + unsigned int idx, + unsigned int freq) { + struct metal_clock *clock = __metal_driver_sifive_pwm0_clock(gpwm); + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + unsigned int cmp_count = __metal_driver_sifive_pwm0_comparator_count(gpwm); + struct __metal_driver_sifive_pwm0 *pwm = (void *)gpwm; + unsigned int clock_rate; + unsigned int count; + unsigned int prescale = 0; + int ret = METAL_PWM_RET_ERR; + + if ((clock != NULL) && (gpwm != NULL) && (idx < cmp_count)) { + clock_rate = clock->vtable->get_rate_hz(clock); + /* Register clock rate change call-backs */ + if (pwm->freq == 0) { + pwm->pre_rate_change_callback.callback = &pre_rate_change_callback; + pwm->pre_rate_change_callback.priv = pwm; + metal_clock_register_pre_rate_change_callback( + clock, &(pwm->pre_rate_change_callback)); + + pwm->post_rate_change_callback.callback = + &post_rate_change_callback; + pwm->post_rate_change_callback.priv = pwm; + metal_clock_register_post_rate_change_callback( + clock, &(pwm->post_rate_change_callback)); + } + + /* Calculate count value for given PWM frequency */ + do { + count = (clock_rate / (1UL << prescale)) / freq; + } while ((count > pwm->max_count) && + (prescale++ < METAL_PWM_MAXPRESCAL)); + + pwm->freq = (clock_rate / (1UL << prescale)) / count; + pwm->count_val = --count; + + /* Update values into registers */ + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCMP0) = count; + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) |= (prescale & 0x0FUL); + ret = METAL_PWM_RET_OK; + +#if defined(METAL_PWM_DEBUG) + printf("PWM requested freq:%u set freq:%u \n", freq, pwm->freq); + printf("CPU Clk:%u Prescale:%u Count:%u \n", clock_rate, + prescale, count); +#endif + } + return ret; +} + +static int +__metal_driver_sifive_pwm0_set_duty(struct metal_pwm *gpwm, unsigned int idx, + unsigned int duty, + metal_pwm_phase_correct_t phase_corr) { + struct __metal_driver_sifive_pwm0 *pwm = (void *)gpwm; + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + unsigned int cmp_count = __metal_driver_sifive_pwm0_comparator_count(gpwm); + int ret = METAL_PWM_RET_ERR; + + /* Check if duty value is within limits, duty cycle cannot be set for + * PWMCMP0 */ + if ((idx > 0) && (idx < cmp_count) && (duty <= METAL_PWM_MAXDUTY)) { + /* Calculate PWM compare count value for given duty cycle */ + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCMP(idx)) = + METAL_PWM_GETCMPVAL(duty); + pwm->duty[idx] = duty; + + /* Enable / Disable phase correct PWM mode */ + if (phase_corr == METAL_PWM_PHASE_CORRECT_ENABLE) { + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) |= + METAL_PWMCFG_CMPCENTER(idx); + } else { + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) &= + ~METAL_PWMCFG_CMPCENTER(idx); + } + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static unsigned int __metal_driver_sifive_pwm0_get_duty(struct metal_pwm *gpwm, + unsigned int idx) { + struct __metal_driver_sifive_pwm0 *pwm = (void *)gpwm; + unsigned int cmp_count = __metal_driver_sifive_pwm0_comparator_count(gpwm); + unsigned int duty = 0; + + /* Check for valid parameters and get configured duty cycle value */ + if ((pwm != NULL) && (idx > 0) && (idx < cmp_count)) { + duty = pwm->duty[idx]; + } + return duty; +} + +static unsigned int +__metal_driver_sifive_pwm0_get_freq(struct metal_pwm *gpwm, unsigned int idx) { + struct __metal_driver_sifive_pwm0 *pwm = (void *)gpwm; + unsigned int freq = 0; + + (void)idx;/* Unused parameter, no support for per channel frequency */ + + /* Check for valid parameters and get configured PWM frequency value */ + if (pwm != NULL) { + freq = pwm->freq; + } + return freq; +} + +static int __metal_driver_sifive_pwm0_trigger(struct metal_pwm *gpwm, + unsigned int idx, + metal_pwm_run_mode_t mode) { + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + int ret = METAL_PWM_RET_ERR; + + (void)idx;/* Unused parameter,for later use */ + + if (base != 0) { + /* Configure for requested PWM run mode */ + if (mode == METAL_PWM_CONTINUOUS) { + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) |= METAL_PWMCFG_DEGLITCH | + METAL_PWMCFG_ZEROCMP | + METAL_PWMCFG_ENALWAYS; + } else { + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) |= METAL_PWMCFG_DEGLITCH | + METAL_PWMCFG_ZEROCMP | + METAL_PWMCFG_ENONESHOT; + } + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static int __metal_driver_sifive_pwm0_stop(struct metal_pwm *gpwm, + unsigned int idx) { + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + int ret = METAL_PWM_RET_ERR; + + (void)idx;/* Unused parameter,for later use */ + + if (base != 0) { + /* Disable always running mode */ + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) &= ~METAL_PWMCFG_ENALWAYS; + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static int +__metal_driver_sifive_pwm0_cfg_interrupt(struct metal_pwm *gpwm, + metal_pwm_interrupt_t flag) { + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + int ret = METAL_PWM_RET_ERR; + + if (base != 0) { + if (flag == METAL_PWM_INTERRUPT_ENABLE) { + /* Enable sticky bit, to make sure interrupts are not forgotten */ + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) |= METAL_PWMCFG_STICKY; + } else { + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) &= ~METAL_PWMCFG_STICKY; + } + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static int __metal_driver_sifive_pwm0_clr_interrupt(struct metal_pwm *gpwm, + unsigned int idx) { + unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); + unsigned int cmp_count = __metal_driver_sifive_pwm0_comparator_count(gpwm); + int ret = METAL_PWM_RET_ERR; + + if ((base != 0) && (idx < cmp_count)) { + /* Clear interrupt pending bit for given PWM comparator */ + METAL_PWM_REGW(METAL_SIFIVE_PWM0_PWMCFG) &= ~METAL_PWMCFG_CMPIP(idx); + ret = METAL_PWM_RET_OK; + } + return ret; +} + +static struct metal_interrupt * +__metal_driver_sifive_pwm0_interrupt_controller(struct metal_pwm *gpwm) { + return __metal_driver_sifive_pwm0_interrupt_parent(gpwm); +} + +static int __metal_driver_sifive_pwm0_interrupt_id(struct metal_pwm *gpwm, + unsigned int idx) { + return __metal_driver_sifive_pwm0_interrupt_lines(gpwm, idx); +} + +__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_pwm0) = { + .pwm.enable = __metal_driver_sifive_pwm0_enable, + .pwm.disable = __metal_driver_sifive_pwm0_disable, + .pwm.set_duty = __metal_driver_sifive_pwm0_set_duty, + .pwm.set_freq = __metal_driver_sifive_pwm0_set_freq, + .pwm.get_duty = __metal_driver_sifive_pwm0_get_duty, + .pwm.get_freq = __metal_driver_sifive_pwm0_get_freq, + .pwm.trigger = __metal_driver_sifive_pwm0_trigger, + .pwm.stop = __metal_driver_sifive_pwm0_stop, + .pwm.cfg_interrupt = __metal_driver_sifive_pwm0_cfg_interrupt, + .pwm.clr_interrupt = __metal_driver_sifive_pwm0_clr_interrupt, + .pwm.get_interrupt_controller = + __metal_driver_sifive_pwm0_interrupt_controller, + .pwm.get_interrupt_id = __metal_driver_sifive_pwm0_interrupt_id, +}; + +#endif /* METAL_SIFIVE_PWM0 */ + +typedef int no_empty_translation_units; diff --git a/src/pwm.c b/src/pwm.c new file mode 100644 index 00000000..e65880c7 --- /dev/null +++ b/src/pwm.c @@ -0,0 +1,36 @@ +/* Copyright 2019 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include + +extern inline int metal_pwm_enable(struct metal_pwm *pwm); +extern inline int metal_pwm_disable(struct metal_pwm *pwm); +extern inline int metal_pwm_set_freq(struct metal_pwm *pwm, unsigned int idx, + unsigned int freq); +extern inline int metal_pwm_set_duty(struct metal_pwm *pwm, unsigned int idx, + unsigned int duty, + metal_pwm_phase_correct_t phase_corr); +extern inline unsigned int metal_pwm_get_duty(struct metal_pwm *pwm, + unsigned int idx); +extern inline unsigned int metal_pwm_get_freq(struct metal_pwm *pwm, + unsigned int idx); +extern inline int metal_pwm_trigger(struct metal_pwm *pwm, + unsigned int idx, + metal_pwm_run_mode_t mode); +extern inline int metal_pwm_stop(struct metal_pwm *pwm, unsigned int idx); +extern inline int metal_pwm_cfg_interrupt(struct metal_pwm *pwm, + metal_pwm_interrupt_t flag); +extern inline int metal_pwm_clr_interrupt(struct metal_pwm *pwm, + unsigned int idx); +extern struct metal_interrupt * +metal_pwm_interrupt_controller(struct metal_pwm *pwm); +extern int metal_pwm_get_interrupt_id(struct metal_pwm *pwm, unsigned int idx); + +struct metal_pwm *metal_pwm_get_device(unsigned int device_num) { + if (device_num >= __METAL_DT_MAX_PWMS) { + return NULL; + } + + return (struct metal_pwm *)__metal_pwm_table[device_num]; +} From 06801853deb7e0f4f165ccf652ae647e3ecdd3ec Mon Sep 17 00:00:00 2001 From: Nandkumar Joshi Date: Fri, 13 Mar 2020 01:17:10 +0530 Subject: [PATCH 2/2] Minor changes in I2C. Fix formatting. GPIO enable IO fix. GPIO IOF register fix. --- metal/drivers/sifive_pwm0.h | 8 +++++--- metal/i2c.h | 2 +- metal/pwm.h | 8 +++++--- src/drivers/sifive_gpio0.c | 2 +- src/drivers/sifive_i2c0.c | 2 +- src/drivers/sifive_pwm0.c | 24 +++++++++++++----------- src/i2c.c | 2 +- src/pwm.c | 14 +++++++------- 8 files changed, 34 insertions(+), 28 deletions(-) diff --git a/metal/drivers/sifive_pwm0.h b/metal/drivers/sifive_pwm0.h index b8efc70f..caa77440 100644 --- a/metal/drivers/sifive_pwm0.h +++ b/metal/drivers/sifive_pwm0.h @@ -1,17 +1,19 @@ -/* Copyright 2019 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #ifndef METAL__DRIVERS__SIFIVE_PWM0_H #define METAL__DRIVERS__SIFIVE_PWM0_H #include -#include #include struct __metal_driver_vtable_sifive_pwm0 { const struct metal_pwm_vtable pwm; }; +/* Max possible PWM channel count */ +#define METAL_MAX_PWM_CHANNELS 16 + __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_pwm0) struct __metal_driver_sifive_pwm0 { @@ -19,7 +21,7 @@ struct __metal_driver_sifive_pwm0 { unsigned int max_count; unsigned int count_val; unsigned int freq; - unsigned int duty[METAL_MAX_PWM0_NCMP]; + unsigned int duty[METAL_MAX_PWM_CHANNELS]; metal_clock_callback pre_rate_change_callback; metal_clock_callback post_rate_change_callback; }; diff --git a/metal/i2c.h b/metal/i2c.h index ec45573f..baf62e5d 100644 --- a/metal/i2c.h +++ b/metal/i2c.h @@ -37,7 +37,7 @@ struct metal_i2c { /*! @brief Get a handle for a I2C device. * @param device_num The index of the desired I2C device. * @return A handle to the I2C device, or NULL if the device does not exist.*/ -struct metal_i2c *metal_i2c_get_device(int device_num); +struct metal_i2c *metal_i2c_get_device(unsigned int device_num); /*! @brief Initialize a I2C device with a certain baud rate. * @param i2c The handle for the I2C device to initialize. diff --git a/metal/pwm.h b/metal/pwm.h index a6d37a4d..600d5a02 100644 --- a/metal/pwm.h +++ b/metal/pwm.h @@ -1,4 +1,4 @@ -/* Copyright 2019 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #ifndef METAL__PWM_H @@ -33,7 +33,8 @@ struct metal_pwm_vtable { metal_pwm_phase_correct_t phase_corr); unsigned int (*get_duty)(struct metal_pwm *pwm, unsigned int idx); unsigned int (*get_freq)(struct metal_pwm *pwm, unsigned int idx); - int (*trigger)(struct metal_pwm *pwm, unsigned int idx, metal_pwm_run_mode_t mode); + int (*trigger)(struct metal_pwm *pwm, unsigned int idx, + metal_pwm_run_mode_t mode); int (*stop)(struct metal_pwm *pwm, unsigned int idx); int (*cfg_interrupt)(struct metal_pwm *pwm, metal_pwm_interrupt_t flag); int (*clr_interrupt)(struct metal_pwm *pwm, unsigned int idx); @@ -110,7 +111,8 @@ inline unsigned int metal_pwm_get_freq(struct metal_pwm *pwm, * @param pwm PWM device handle. * @param idx PWM channel id. * @return 0 If no error.*/ -inline int metal_pwm_trigger(struct metal_pwm *pwm, unsigned int idx, metal_pwm_run_mode_t mode) { +inline int metal_pwm_trigger(struct metal_pwm *pwm, unsigned int idx, + metal_pwm_run_mode_t mode) { return pwm->vtable->trigger(pwm, idx, mode); } diff --git a/src/drivers/sifive_gpio0.c b/src/drivers/sifive_gpio0.c index c536c324..1324eb6e 100644 --- a/src/drivers/sifive_gpio0.c +++ b/src/drivers/sifive_gpio0.c @@ -100,7 +100,7 @@ int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source, long base = __metal_driver_sifive_gpio0_base(ggpio); __METAL_ACCESS_ONCE( - (__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_SEL)) &= ~source; + (__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_SEL)) |= source; __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) |= dest; diff --git a/src/drivers/sifive_i2c0.c b/src/drivers/sifive_i2c0.c index e8ecc584..ec79bbc3 100644 --- a/src/drivers/sifive_i2c0.c +++ b/src/drivers/sifive_i2c0.c @@ -260,7 +260,7 @@ static int __metal_driver_sifive_i2c0_write(struct metal_i2c *i2c, } } else { - /* Write address failed */ + /* I2C device not initialized, return error */ METAL_I2C_LOG("I2C device not initialized.\n"); ret = METAL_I2C_RET_ERR; } diff --git a/src/drivers/sifive_pwm0.c b/src/drivers/sifive_pwm0.c index a602fcdc..415d4682 100644 --- a/src/drivers/sifive_pwm0.c +++ b/src/drivers/sifive_pwm0.c @@ -1,4 +1,4 @@ -/* Copyright 2019 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #include @@ -21,7 +21,7 @@ #define METAL_PWMCFG_ENONESHOT (1UL << 13) #define METAL_PWMCFG_CMPCENTER(x) (1UL << (16 + x)) #define METAL_PWMCFG_CMPIP(x) (1UL << (28 + x)) -#define METAL_SIFIVE_PWM0_PWMCMP(x) METAL_SIFIVE_PWM0_PWMCMP0 + x * 4 +#define METAL_SIFIVE_PWM0_PWMCMP(x) (METAL_SIFIVE_PWM0_PWMCMP0 + (x * 4)) /* Macros to access registers */ #define METAL_PWM_REG(offset) ((base + offset)) @@ -40,12 +40,14 @@ #error *** Unsupported endianess *** #endif +#if (METAL_MAX_PWM0_NCMP > METAL_MAX_PWM_CHANNELS) +#error *** METAL_MAX_PWM_CHANNELS exceeded *** +#endif + /* Return values */ #define METAL_PWM_RET_OK 0 #define METAL_PWM_RET_ERR -1 -#define METAL_PWM_DEBUG - static void pre_rate_change_callback(void *priv) { struct metal_pwm *gpwm = priv; /* Disable active PWM instance. */ @@ -172,8 +174,8 @@ static int __metal_driver_sifive_pwm0_set_freq(struct metal_pwm *gpwm, #if defined(METAL_PWM_DEBUG) printf("PWM requested freq:%u set freq:%u \n", freq, pwm->freq); - printf("CPU Clk:%u Prescale:%u Count:%u \n", clock_rate, - prescale, count); + printf("CPU Clk:%u Prescale:%u Count:%u \n", clock_rate, prescale, + count); #endif } return ret; @@ -222,12 +224,12 @@ static unsigned int __metal_driver_sifive_pwm0_get_duty(struct metal_pwm *gpwm, return duty; } -static unsigned int -__metal_driver_sifive_pwm0_get_freq(struct metal_pwm *gpwm, unsigned int idx) { +static unsigned int __metal_driver_sifive_pwm0_get_freq(struct metal_pwm *gpwm, + unsigned int idx) { struct __metal_driver_sifive_pwm0 *pwm = (void *)gpwm; unsigned int freq = 0; - (void)idx;/* Unused parameter, no support for per channel frequency */ + (void)idx; /* Unused parameter, no support for per channel frequency */ /* Check for valid parameters and get configured PWM frequency value */ if (pwm != NULL) { @@ -242,7 +244,7 @@ static int __metal_driver_sifive_pwm0_trigger(struct metal_pwm *gpwm, unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); int ret = METAL_PWM_RET_ERR; - (void)idx;/* Unused parameter,for later use */ + (void)idx; /* Unused parameter,for later use */ if (base != 0) { /* Configure for requested PWM run mode */ @@ -265,7 +267,7 @@ static int __metal_driver_sifive_pwm0_stop(struct metal_pwm *gpwm, unsigned long base = __metal_driver_sifive_pwm0_control_base(gpwm); int ret = METAL_PWM_RET_ERR; - (void)idx;/* Unused parameter,for later use */ + (void)idx; /* Unused parameter,for later use */ if (base != 0) { /* Disable always running mode */ diff --git a/src/i2c.c b/src/i2c.c index f9e77225..6c342aa3 100644 --- a/src/i2c.c +++ b/src/i2c.c @@ -18,7 +18,7 @@ extern inline int metal_i2c_transfer(struct metal_i2c *i2c, unsigned int addr, extern inline int metal_i2c_get_baud_rate(struct metal_i2c *i2c); extern inline int metal_i2c_set_baud_rate(struct metal_i2c *i2c, int baud_rate); -struct metal_i2c *metal_i2c_get_device(int device_num) { +struct metal_i2c *metal_i2c_get_device(unsigned int device_num) { #if __METAL_DT_MAX_I2CS > 0 if (device_num < __METAL_DT_MAX_I2CS) { return (struct metal_i2c *)__metal_i2c_table[device_num]; diff --git a/src/pwm.c b/src/pwm.c index e65880c7..15e4e6ec 100644 --- a/src/pwm.c +++ b/src/pwm.c @@ -1,4 +1,4 @@ -/* Copyright 2019 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #include @@ -15,8 +15,7 @@ extern inline unsigned int metal_pwm_get_duty(struct metal_pwm *pwm, unsigned int idx); extern inline unsigned int metal_pwm_get_freq(struct metal_pwm *pwm, unsigned int idx); -extern inline int metal_pwm_trigger(struct metal_pwm *pwm, - unsigned int idx, +extern inline int metal_pwm_trigger(struct metal_pwm *pwm, unsigned int idx, metal_pwm_run_mode_t mode); extern inline int metal_pwm_stop(struct metal_pwm *pwm, unsigned int idx); extern inline int metal_pwm_cfg_interrupt(struct metal_pwm *pwm, @@ -28,9 +27,10 @@ metal_pwm_interrupt_controller(struct metal_pwm *pwm); extern int metal_pwm_get_interrupt_id(struct metal_pwm *pwm, unsigned int idx); struct metal_pwm *metal_pwm_get_device(unsigned int device_num) { - if (device_num >= __METAL_DT_MAX_PWMS) { - return NULL; +#if __METAL_DT_MAX_PWMS > 0 + if (device_num < __METAL_DT_MAX_PWMS) { + return (struct metal_pwm *)__metal_pwm_table[device_num]; } - - return (struct metal_pwm *)__metal_pwm_table[device_num]; +#endif + return NULL; }