drivers: clock_control: Add PWM clock device

Adds a clock control device for a PWM node, allowing the PWM
to be controlled using the clock control API.

It is a similar idea to the device driver in linux:
linux/Documentation/devicetree/bindings/clock/pwm-clock.yaml

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
Andriy Gelman 2023-06-11 17:07:42 -04:00 committed by Carles Cufí
commit 0d1fa268bb
13 changed files with 411 additions and 0 deletions

View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(pwm_clock)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2023 Andriy Gelman
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
pwmclock: pwmclock {
status = "okay";
compatible = "pwm-clock";
#clock-cells = <1>;
clock-frequency = <1000000>;
pwms = <&pwm0 0 PWM_KHZ(1000) PWM_POLARITY_NORMAL>;
};
samplenode: samplenode {
status = "okay";
compatible = "test-clock-control-pwm-clock";
clocks = <&pwmclock 0>;
};
};
&pwm0 {
prescaler = <1>;
};

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Andriy Gelman
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
pwmclock: pwmclock {
status = "okay";
compatible = "pwm-clock";
#clock-cells = <1>;
clock-frequency = <1000000>;
pwms = <&pwm_ccu40 2 PWM_KHZ(1000) PWM_POLARITY_NORMAL>;
};
samplenode: samplenode {
status = "okay";
compatible = "test-clock-control-pwm-clock";
clocks = <&pwmclock 0>;
};
};
&pwm_ccu40 {
status = "okay";
slice-prescaler = <0 0 0 0>;
};

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Andriy Gelman
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
pwmclock: pwmclock {
status = "okay";
compatible = "pwm-clock";
#clock-cells = <1>;
clock-frequency = <1000000>;
pwms = <&pwm_ccu80 0 PWM_KHZ(1000) PWM_POLARITY_NORMAL>;
};
samplenode: samplenode {
status = "okay";
compatible = "test-clock-control-pwm-clock";
clocks = <&pwmclock 0>;
};
};
&pwm_ccu80 {
status = "okay";
slice-prescaler = <0 0 0 0>;
};

View file

@ -0,0 +1,10 @@
description: Example binding for a node using a PWM clock
compatible: "test-clock-control-pwm-clock"
include: base.yaml
properties:
clocks:
required: true
description: Clock phandle array

View file

@ -0,0 +1,2 @@
CONFIG_ZTEST=y
CONFIG_CLOCK_CONTROL=y

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2023 Andriy Gelman <andriy.gelman@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/ztest.h>
#define NODELABEL DT_NODELABEL(samplenode)
static const struct device *clk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(NODELABEL));
static void *pwm_clock_setup(void)
{
int ret;
uint32_t clock_rate;
uint32_t clock_rate_dt = DT_PROP_BY_PHANDLE(NODELABEL, clocks, clock_frequency);
zassert_equal(device_is_ready(clk_dev), true, "%s: PWM clock device is not ready",
clk_dev->name);
ret = clock_control_get_rate(clk_dev, 0, &clock_rate);
zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate",
clk_dev->name, ret);
zassert_equal(clock_rate_dt, clock_rate,
"%s: devicetree clock rate mismatch. Expected %dHz Fetched %dHz",
clk_dev->name, clock_rate_dt, clock_rate);
ret = clock_control_on(clk_dev, 0);
zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_on", clk_dev->name, ret);
return NULL;
}
ZTEST(pwm_clock, test_clock_control_get_rate)
{
int ret;
uint32_t clock_rate;
ret = clock_control_get_rate(clk_dev, 0, &clock_rate);
zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate",
clk_dev->name, ret);
}
ZTEST(pwm_clock, test_clock_control_set_rate)
{
int ret;
uint32_t clock_rate, clock_rate_new;
ret = clock_control_get_rate(clk_dev, 0, &clock_rate);
zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate",
clk_dev->name, ret);
clock_rate /= 2;
ret = clock_control_set_rate(clk_dev, 0, (clock_control_subsys_rate_t)clock_rate);
zassert_equal(0, ret, "%s: unexpected err (%d) from clock_control_set_rate",
clk_dev->name, ret);
ret = clock_control_get_rate(clk_dev, 0, &clock_rate_new);
zassert_equal(0, ret, "%s: Unexpected err (%d) from clock_control_get_rate",
clk_dev->name, ret);
zassert_equal(clock_rate, clock_rate_new,
"%s: Clock rate mismatch. Expected %dHz Fetched %dHz", clk_dev->name,
clock_rate, clock_rate_new);
}
ZTEST_SUITE(pwm_clock, NULL, pwm_clock_setup, NULL, NULL, NULL);

View file

@ -0,0 +1,7 @@
tests:
drivers.clock.pwm_clock:
filter: dt_compat_enabled("pwm-clock") and dt_compat_enabled("test-clock-control-pwm-clock")
tags:
- drivers
- clock
- pwm