This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM625: About TI EHRPWM driver and kernel abstraction (pwm.h api)

Part Number: AM625

Tool/software:

I'm resuming the manipulation of EPWM modules at the kernel level. I went through the process of activating kconfig and the TI API itself in the kernel to create the driver for the module with the probe itself. Ok, so far so good.

echo val > /sys/class/pwm/pwmchip0/pwm0/duty_cycle

However, from what I saw in the TI examples, the only way is to write directly through sysfs with the ops interaction. Great, however, how can I use the kernel's standard PWM API to manipulate the Texas driver?

The node in question in the DTS is this:

	epwm0: pwm@23000000 {
		compatible = "ti,am64-epwm", "ti,am3352-ehrpwm";
		#pwm-cells = <3>;
		reg = <0x00 0x23000000 0x00 0x100>;
		power-domains = <&k3_pds 86 TI_SCI_PD_EXCLUSIVE>;
		clocks = <&epwm_tbclk 0>, <&k3_clks 86 0>;
		clock-names = "tbclk", "fck";
		status = "disabled";
	};

The way pwm-tiehrpwm.c registers the ehrpwmchip driver in the kernel, via the probe, is:

static int ehrpwm_pwm_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct ehrpwm_pwm_chip *pc;
	struct clk *clk;
	int ret;

	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
	if (!pc)
		return -ENOMEM;

	clk = devm_clk_get(&pdev->dev, "fck");
	if (IS_ERR(clk)) {
		if (of_device_is_compatible(np, "ti,am33xx-ecap")) {
			dev_warn(&pdev->dev, "Binding is obsolete.\n");
			clk = devm_clk_get(pdev->dev.parent, "fck");
		}
	}

	if (IS_ERR(clk))
		return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get fck\n");

	pc->clk_rate = clk_get_rate(clk);
	if (!pc->clk_rate) {
		dev_err(&pdev->dev, "failed to get clock rate\n");
		return -EINVAL;
	}

	pc->chip.dev = &pdev->dev;
	pc->chip.ops = &ehrpwm_pwm_ops;
	pc->chip.npwm = NUM_PWM_CHANNEL;

	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(pc->mmio_base))
		return PTR_ERR(pc->mmio_base);

	/* Acquire tbclk for Time Base EHRPWM submodule */
	pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
	if (IS_ERR(pc->tbclk))
		return dev_err_probe(&pdev->dev, PTR_ERR(pc->tbclk), "Failed to get tbclk\n");

	ret = clk_prepare(pc->tbclk);
	if (ret < 0) {
		dev_err(&pdev->dev, "clk_prepare() failed: %d\n", ret);
		return ret;
	}

	ret = pwmchip_add(&pc->chip);
	if (ret < 0) {
		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
		goto err_clk_unprepare;
	}

	platform_set_drvdata(pdev, pc);
	pm_runtime_enable(&pdev->dev);

	return 0;

err_clk_unprepare:
	clk_unprepare(pc->tbclk);

	return ret;
}

Currently, I'm trying to get the device through the kernel's standard pwm api like this:

- module_node is pointing to the node above from dtsi.

    struct platform_device *module_device   = NULL;
    struct pwm_device *epwm_module          = NULL;
    
    module_device = of_find_device_by_node(module_node);
    if(module_device == NULL)
    {
        printk(KERN_ERR "%s: Error searching epwm device\n", DEVICE_NAME);
    }

    epwm_module = (struct pwm_device *)platform_get_drvdata(module_device);
    if(epwm_module == NULL)
    {
        printk(KERN_ERR "%s: Error alloc epwm device\n", DEVICE_NAME);
    }

To manipulate the module, I am using this snippet:

struct pwm_device *epwm_module;
    
struct pwm_state state;
struct pwm_device *device;
struct pwm_chip *chip;
    
device  = epwm_module;
chip    = epwm_module->chip;
    
state.period = frequency;
state.duty_cycle = duty_cycle;
state.polarity = 0;
state.enabled = (command != DISABLE) ? true : false;

epwm_module->chip->ops->apply(chip, device, &state);

However, I'm getting a kernel exception when doing these operations. I didn't find any examples in my research of the kernel's pwm.h api being used in a texas driver. I saw that it has its own structures to describe the device.

  • Hello Rafael,

    Unfortunately, we are unable to support questions about custom driver development on the TI forums.

    With that said, our PWMs are regularly used for peripherals like backlights. Perhaps you could find the driver by looking at sample devicetree files and take a look at how those work?

    Regards,

    Nick