PWM in Linux driver insmod - timer

I am trying to insmod a pwm triple timer counter(TTC) driver for Zynq PS. The dmesg log is:
TTC: Inside probe function
pwm-cadence f8001000.timer: PWM 0 has clock source 0 at 108333336 Hz
pwm-cadence f8001000.timer: PWM 1 has clock source 0 at 108333336 Hz
pwm-cadence f8001000.timer: PWM 2 has clock source 0 at 108333336 Hz
pwm-cadence f8001000.timer: cannot add pwm chip (error -22)
Does the EINVAL (error -22) function occur when certain fields in struct cpwm->chip are uninitialised?
I am a newbie in this field. So any tips would be appreciated.
static int cadence_pwm_probe(struct platform_device *pdev)
{
struct cadence_pwm_chip *cpwm;
struct resource *r_mem;
int ret;
struct device_node *node = pdev->dev.of_node;
const __be32 *value;
int rlen;
char propname[24];
int i;
struct cadence_pwm_pwm *pwm;
printk(KERN_DEBUG "TTC: Inside probe function\n");
cpwm = devm_kzalloc(&pdev->dev, sizeof(*cpwm), GFP_KERNEL);
if (!cpwm)
return -ENOMEM;
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cpwm->base = devm_ioremap_resource(&pdev->dev, r_mem);
if (IS_ERR(cpwm->base))
return PTR_ERR(cpwm->base);
for (i = 0; i < CPWM_NUM_PWM; i ++) {
pwm = cpwm->pwms + i;
snprintf(propname, sizeof(propname), "xlnx,ttc-clk%d-freq-hz", i);
value = of_get_property(node, propname, &rlen);
if (value)
pwm->clk_hz = be32_to_cpup(value);
else {
dev_err(&pdev->dev, "missing %s property1", propname);
return -ENODEV;
}
snprintf(propname, sizeof(propname), "xlnx,ttc-clk%d-clksrc", i);
value = of_get_property(node, propname, &rlen);
if (value)
pwm->source = be32_to_cpup(value);
else {
dev_err(&pdev->dev, "missing %s property2", propname);
return -ENODEV;
}
dev_info(&pdev->dev, "PWM %d has clock source %d at %d Hz", i, pwm->source, pwm->clk_hz);
}
cpwm->chip.dev = &pdev->dev;
cpwm->chip.ops = &cadence_pwm_ops;
cpwm->chip.npwm = CPWM_NUM_PWM;
cpwm->chip.base = -1;
ret = pwmchip_add(&cpwm->chip);
if (ret < 0) {
dev_err(&pdev->dev, "cannot add pwm chip (error %d)", ret);
return ret;
}

Well, the code looks decent. This means that adding PWM chip must not fail - all fields required are set and they are fine.
However, EINVAL could still be returned as per the only remaining reason, namely, because support for PWM (CONFIG_PWM) has been disabled in the kernel build config. This follows from include/linux/pwm.h file where conditional compilation is used. So, if CONFIG_PWM option has been enabled, then a proper symbol exists. And, when you build your driver, this function prototype will be used from the header. But if the kernel has been built without PWM support, then inline function will be used during driver compilation, which is a simple stub to return EINVAL in any case.
All in all, you need to check your build configuration properly.

Related

Reading Device Hardware Register

I am attempting to create a device driver, albeit a naïvely simple one, which simply reads the status of a hardware register representing a dip switch. Very new at this and I am rather unsure of where to find adequate resources on the topic. Would be desirable to expose the data in sysfs.
DTS:
switches#c1000000 {
compatible = "test, test-switches";
label = "security_switch";
reg = c1000000;
mask = 0x1000;
status = "okay";
};
Driver:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
/* Declare the probe and remove functions */
static int dt_probe(struct platform_device *pdev);
static int dt_remove(struct platform_device *pdev);
/* Declare the read switch function */
int read_switch(struct platform_device *pdev);
int read_switch(struct platform_device *pdev)
{
static void *reg_data;
int ret;
unsigned int adr_reg, bit_mask;
struct device *dev = &pdev->dev;
ret = device_property_read_u32(dev, "reg", &adr_reg);
if(ret) {
printk("Error! Could not read 'reg'\n");
return -1;
}
printk("Reg read as - %d\n", adr_reg);
ret = device_property_read_u32(dev, "mask", &bit_mask);
if(ret) {
printk("Error! Could not read 'mask'\n");
return -1;
}
printk("Mask read as - %d\n", bit_mask);
reg_data = ioremap(adr_reg, bit_mask);
printk("Value #%d", adr_reg);
printk("-%d ", bit_mask);
printk(": %d\n", ioread32(reg_data));
iounmap(reg_data);
return 0;
}
/**
* #brief This structure is used to match the DTS entry
*/
static const struct of_device_id switch_driver_ids[] = {
{
.compatible = "test,test-switches",
}, {}
};
MODULE_DEVICE_TABLE(of, switch_driver_ids);
/**
* #brief Platform Driver definition including functions used for adding, removing and probing
* the device
*/
static struct platform_driver switch_driver = {
.probe = dt_probe,
.remove = dt_remove,
.driver = {
.name = "switch_device_driver",
.of_match_table = switch_driver_ids,
},
};
/**
* #brief This function is called loading the driver
*/
static int dt_probe(struct platform_device *pdev) {
struct device *dev = &pdev->dev;
int ret;
const char *label;
const char *status;
unsigned int reg;
printk("dt_probe - Probing function!\n");
/* Check for device properties */
if(!device_property_present(dev, "label")) {
printk("dt_probe - Error! Device property 'label' not found!\n");
return -1;
}
printk("dt_probe - Error! Device property 'label' found!\n");
if(!device_property_present(dev, "status")) {
printk("dt_probe - Error! Device property 'status' not found!\n");
return -1;
}
printk("dt_probe - Error! Device property 'status' found!\n");
if(!device_property_present(dev, "reg")) {
printk("dt_probe - Error! Device property 'reg' not found!\n");
return -1;
}
printk("dt_probe - Error! Device property 'reg' found!\n");
/* Read device properties */
ret = device_property_read_string(dev, "label", &label);
if(ret) {
printk("dt_probe - Error! Could not read 'label'\n");
return -1;
}
printk("dt_probe - label: %s\n", label);
ret = device_property_read_string(dev, "status", &status);
if(ret) {
printk("dt_probe - Error! Could not read 'status'\n");
return -1;
}
printk("dt_probe - status: %s\n", status);
ret = device_property_read_u32(dev, "reg", &reg);
if(ret) {
printk("dt_probe - Error! Could not read 'reg'\n");
return -1;
}
printk("dt_probe - reg: %d\n", reg);
read_switch(pdev);
return 0;
}
/**
* #brief This function is called unloading the driver
*/
static int dt_remove(struct platform_device *pdev) {
printk("dt_probe - Removing driver\n");
return 0;
}
/**
* #brief This function is called when the module is loaded into the kernel
*/
static int __init init_drv(void) {
printk("dt_probe - Loading the driver...\n");
if(platform_driver_register(&switch_driver)) {
printk("dt_probe - Error! Could not load driver\n");
return -1;
}
return 0;
}
/**
* #brief This function is called when the module is removed from the kernel
*/
static void __exit exit_drv(void) {
printk("dt_probe - Unload driver");
platform_driver_unregister(&switch_driver);
}
module_init(init_drv);
module_exit(exit_drv);
There's basic documentation on sysfs here:
https://docs.kernel.org/filesystems/sysfs.html
With more info in include/linux/sysfs.h and include/linux/device.h.
Generally speaking though: best way to learn this stuff is read kernel docs (Documentation folder under kernel source tree), Kernel source itself, mailing lists & other well-established/written mainline drivers.
This used to be a decent primer on device drivers, it's very dated at this point, but some concepts may still apply: https://lwn.net/Kernel/LDD3/
Not sure I follow how a DIP switch get's "mapped" to a particular register. If this is GPIO pins on your SOC, then the -easy- way to get sysfs access is to use GPIO via sysfs, though it can be tricky sorting out pin numbers depending on your platform.
That said, if this really does need it's own driver--then usually you'll want to use DEVICE_ATTR family of macros to define your attribute and then either sysfs_create_group / sysfs_remove_group or sysfs_add_file / sysfs_remove_file to register/unregister in your probe / remove.

Asynchronus DMA mem2mem copy doesn't transfer data

I'm working on a device driver that needs to preform mem to mem copies via dma on a Beaglebone Black (ARM) with Linux Kernel 5.4.106. So far I've managed to successfully request a mem to mem compatible channel (and release it when I'm done), but I'm unable to perform the actual transfer.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dmaengine.h>
struct dma_chan *chan;
void *src;
void *dst;
static int __init mod_init(void)
{
dma_cap_mask_t mask;
int ret;
struct dma_async_tx_descriptor *tx = NULL;
dma_cookie_t cookie;
int *writer;
enum dma_status status;
printk("mod_init called\n");
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
chan = dma_request_channel(mask, NULL, NULL);
if(!chan){
printk("no mem2mem channels available");
ret = -EAGAIN;
goto fail_chan;
}
printk("requested channel");
src = kzalloc(16,GFP_KERNEL);
if(src == NULL){
ret = -ENOMEM;
goto fail_m1;
}
dst = kzalloc(16,GFP_KERNEL);
if(dst == NULL){
ret = -ENOMEM;
goto fail_m2;
}
writer = (int *)src;
*writer = 20;
tx = chan->device->device_prep_dma_memcpy(chan, virt_to_phys(dst), virt_to_phys(src), 16, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
if (!tx) {
printk("prep error");
}
printk("slave configured");
cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
printk("submit error");
}
dma_async_issue_pending(chan);
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
if(status != DMA_COMPLETE){
printk("something went wrong");
}
printk("dst: %d, src: %d", *(int *)dst, *(int *)src);
printk("done");
return 0;
fail_m2:
kfree(src);
fail_m1:
dma_release_channel(chan);
fail_chan:
return ret;
}
static void __exit mod_exit(void)
{
printk("mod_exit called\n");
dma_release_channel(chan);
printk("dst: %d, src: %d", *(int *)dst, *(int *)src);
kfree(src);
kfree(dst);
printk("released channel");
}
module_init( mod_init );
module_exit( mod_exit );
MODULE_AUTHOR("Me");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DMA engine test.");
This kernel module compiles without any issues and when installed does not cause any errors. Eventho the cookie returns a DMA_COMPLETE status, the value in dst stays 0 (it should become 20).
Most of the code is based on the dmatest driver, which preforms flawlessly, but my copy is missing the mark.
What could be the issue here? Am I missing a step?
Try adding GFP_DMA flag to your kzalloc() calls - the memory you allocate should be suitable for DMA transfers, that is platform-dependent.

FTDI FT232H communication with LM77 over I2C

I am trying to get a temperature readout from a LM77 using I2C communication with and FTDI FT232H. I don't think it is a hardware problem since I have checked the connections along with multiple colleagues. The communication with the PC to the FT232H is okay, it is initializing and everything is good on that end. The FT232H sends a read setup byte and gets an ACK from the LM77. After that there is no more data. I expect the LM77 to send 10 bits of data for a temperature readout, but it is not. This is what the readout looks like on a logic probe.
I would expect to then see an additional two bytes come in after the ACK but am getting nothing. The code is pretty straightforward and I am using the libMPSSE I2C API. The address I am using 0x48 comes from the address given in the datasheet bit shifted right by 1. I do not understand why I am getting an ACK but no temperature readout after. The ftStatus for the read gives an error code FT_DEVICE_NOT_FOUND. I am not sure why it's giving this error code if there is an ACK.
#include <stdio.h>
#include <stdlib.h>
#include "libMPSSE_i2c.h"
#define DEVICE_ADDR 0x48
FT_STATUS ftStatus;
FT_HANDLE ftHandle;
int i2cInit(void)
{
int numChannels = 0;
FT_DEVICE_LIST_INFO_NODE chanInfo;
ChannelConfig chConfig = {.ClockRate = 100000,
.LatencyTimer = 255,
.Options = 0x0000};
ftStatus = I2C_GetNumChannels(&numChannels);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Number of channels: %d\n", numChannels);
}
ftStatus = I2C_GetChannelInfo(0, &chanInfo);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Channel info obtained\n");
}
ftStatus = I2C_OpenChannel(0, &ftHandle);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Channel opened\n");
}
ftStatus = I2C_InitChannel(ftHandle, &chConfig);
if (ftStatus != FT_OK)
{
return -1;
}
else
{
printf("Channel initialized\n");
}
}
int lm77ReadTemp()
{
unsigned char writeBuffer[20] = {0};
unsigned char readBuffer[20] = {0};
unsigned char bytesTransferred = 0;
unsigned int bytesRead = 0;
ftStatus = I2C_DeviceRead(ftHandle, DEVICE_ADDR, 2, readBuffer, &bytesRead, I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT);
if (ftStatus != FT_OK)
{
printf("Read failed status code %d\n", ftStatus);
}
}
int main(void)
{
i2cInit();
lm77ReadTemp();
return 0;
}
The problem was on the hardware side. The MPSSE engine does not have bidirectional pins. On the FTDI chip side, you need a separate pin for SDA_out and SDA_in. There is a diagram in the FTDI documentation that shows it. If you don't have the pins connected like this you won't receive any data from the I2C slave.

Why is membase adress different each time kernel module is loaded?

I've been building a RTDM UART driver by using the Linux version as an example. The UART base address is supposed to be 0x80070000, and when using the linux driver there is no problem as dmesg show:
80070000.serial: ttyAPP3 at MMIO 0x80070000 (irq = 234, base_baud = 1500000) is a 80070000.serial
mxs-auart 80070000.serial: Found APPUART 3.1.0
However, when I'm using the driver I'm builing I get a different adress each time I'm loading the module (such as 0xc8df6000) and none of them are correct.
Here's the probe function I'm using:
static int rt_mxs_auart_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxs_auart_dt_ids, &pdev->dev);
int ret;
struct resource *r;
struct rtdm_device *dev;
struct rt_mxs_auart_port *s;
//allocate managed kernel memory
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
ret = rt_serial_mxs_probe_dt(s, pdev);
if (ret < 0){
return ret;
}
if (of_id) {
pdev->id_entry = of_id->data;
s->devtype = pdev->id_entry->driver_data;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENXIO;
//get irq line
s->irq = platform_get_irq(pdev, 0);
if (s->irq < 0)
return -ENODEV;
//base memory
s->membase = ioremap(r->start, resource_size(r));
if (IS_ERR(s->membase))
return PTR_ERR(s->membase);
/*define the rtdm_device*/
dev = &s->rtdm_dev;
dev->driver = &ida_driver;
dev->label = "xeno_ida";
dev->device_data = s;
ret = mxs_get_clks(s, pdev); //activate clocks
if (ret)
return ret;
s->uartclk = clk_get_rate(s->clk);
s->fifosize = MXS_AUART_FIFO_SIZE;
mxs_init_regs(s);
ret = rtdm_dev_register(dev); //register driver in RTDM space
if (ret)
return ret;
platform_set_drvdata(pdev, s); //add device-related data to device struct
pr_info("Probe: Successful\n");
pr_info("%s on IMX UART%d: membase=0x%p irq=%d uartclk=%d\n",
dev->name, pdev->id, s->membase, s->irq, s->uartclk);
return 0;
}
which is based on mxs-auart.c and rt_imx_uart.c.
For membase I'm using the same code as mxs-auart.c which is why I don't understand why I'm having this issue. My driver also freezes after some time when I try to rmmod it so I wonder if it is caused by this.
Would appreciate any help!
The return value of ioremap is a virtual address, not a physical one. It could be anywhere in the virtual address space.
The physical address is stored in r->start (the input of ioremap).

Data bus error when using ioread32 in PCIE driver

I am developing a PCIE device driver for Openwrt, which is also a linux system. Here is a weird situation. After Initializing the driver in probe function, I can read(by ioread32) correct data (preset value:123456) from the buffer address obtained from ioremap_nocache. Then when I try to read it every 1 second in periodic timer interrupt handler, the function ioread32 will crash and the serial console presents a Data bus error. Below are code details.
// content of function my_driver_request_mem, this function is called in probe function
int my_driver_request_mem(struct gps_time *gt) {
u32 start, len;
int ret;
int bar = 0;
u32 flags;
ret = pcim_iomap_regions(gt->pdev, BIT(0), "My Driver");
if (ret) {
gt_log("Fail to request IO mem: err: %d\n", ret);
return ret;
}
// gt is a custom struct, and gt->pdev is the pci_dev struct
// obtained from probe function
start = pci_resource_start(gt->pdev, bar);
len = pci_resource_len(gt->pdev, bar);
flags = pci_resource_flags(gt->pdev, bar);
printk(KERN_ALERT "region start: 0x%x, len: %u\n", start, len);
printk(KERN_ALERT "region flags: 0x%x\n", flags);
gt->buffer = ioremap_nocache(start, len);
gt->buffer_len = len;
gt->buffer_start = start;
return 0;
}
Afte the function above is invoked, I read data through gt->buffer:
u32 d = 0;
d = ioread32(gt->buffer); // this operation does not cause fatal error
printk(KERN_ALERT "initial value is: %u", d);
By reading the console output, the ioread32 here is successful, and the right value 123456 is printed. Then I start a timer to read data multiple times
setup_timer(&gt->g_timer, _gps_timer_handler, gt);
mod_timer(&gt->g_timer, jiffies + msecs_to_jiffies(20000));
printk(KERN_ALERT "GPS_TIME: timer created.\n");
The handler function is quit simple:
void _gps_timer_handler(unsigned long data) {
struct gps_time *gt = (struct gps_time*)data;
u32 d;
d = ioread32(gt->buffer); // fatal error in this line
printk(KERN_ALERT "Value: %u\n", d);
mod_timer(&gt->g_timer, jiffies + msecs_to_jiffies(1000));
}
The ioread32 here will cause a fatal error here, and the error info is:
Data bus error, epc == 82db8030, ra == 8009a000
Oops[#1]
CPU: 0 PID: 853 Comm: dropbearkey Tainted: G W 4.4.14 #2
task: 82dd1900 ti:8209a000 task.ti: 8209a000
...
(bunch of numbers)
...
Status: 1100d403 KERNEL EXL IE
Cause : 8080001c (ExcCode 07)
PrId: 0001974c (MIPS 74Kc)
...
First I though this is because IO process should not be done in interrupt context, so I put ioread32 in a tasklet, and invoke that tasklet by tasklet_schedule, but it still fails.
======== Update
A. Below are my ->probe function:
static int gps_time_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret = 0;
struct gps_time *gt;
u8 tmp = 0;
u32 bar_val = 0;
u8 csz = 0;
unsigned long start, end, len, flag;
int bar = 0;
if (gps_time_global_time) {
printk(KERN_ALERT "GPS_TIME: more than one device detected\n");
return -1;
}
gt = gps_time_alloc();
if (gt == NULL) {
printk(KERN_WARNING "GPS_TIME: out of memory\n");
return -ENOMEM;
}
gt->pdev = pdev;
gt->irq = pdev->irq;
ret = pcim_enable_device(pdev);
if (ret) {
printk(KERN_ALERT "GPS_TIME: Fail to enable device %d\n", ret);
goto err;
}
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
printk(KERN_WARNING "GPS_TIME: 32-bit DMA not available\n");
return ret;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
printk(KERN_WARNING "GPS_TIME: 32-bit DMA consistent DMA enable failed\n");
return ret;
}
my_driver_request_mem(gt);
ret = pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &tmp);
if (ret) {
printk(KERN_ALERT "GPS_TIME: Fail to read cache line size\n");
goto err;
}
if (tmp == 0) {
printk(KERN_ALERT "GPS_TIME: Write pci cache line size\n");
pci_write_config_byte(
pdev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / sizeof(u32));
}
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
pci_set_master(pdev);
pci_set_drvdata(pdev, gt);
// This function is very simple. I just create timer here. The first ioread32 is also included in this function.
gps_time_init_device(gt);
ret = request_irq(pdev->irq, gps_time_isq, IRQF_SHARED, "gps_time", gt);
if (ret) {
printk(KERN_ALERT "GPS_TIME: Fail to request IRQ: %d", ret);
goto err_irq;
}
return 0;
err_region:
pci_release_regions(pdev);
err_irq:
err:
gps_time_free(gt);
return ret;
}
B. More info about the device:
This device is a self-designed chip with PCIE interface. It is built around a Altera Cyclone IV FPGA. The firmware in the chip does nothing except writing constant 123456 into its memory.

Resources