[英]Custom Linux serdev driver for ST7580 PLC modem
I have a ST7580 Power line communication modem connected to a BeagleBone Black device running Debian Linux, kernel v4.19.我有一个 ST7580 电力线通信调制解调器,它连接到运行 Debian Linux、kernel v4.19 的 BeagleBone Black 设备。 I am trying to communicate with the modem using a custom serial driver (using the SERDEV model) which is based on some samples.我正在尝试使用基于某些示例的自定义串行驱动程序(使用 SERDEV 模型)与调制解调器通信。 I have compiled it as a kernel module named st7580km.ko and used modprobe
to insert it into the kernel. Since I want to use a DeviceTree overlay to load the driver for this peripheral device, I have copied and modified the BONE-UART1.dts and named it as BONE-ST7580.dts with the following content:我将其编译为一个名为st7580km.ko的 kernel 模块,并使用modprobe
将其插入到 kernel 中。由于我想使用 DeviceTree 覆盖加载此外围设备的驱动程序,因此我复制并修改了BONE-UART1.dts并将其命名为BONE-ST7580.dts ,内容如下:
/dts-v1/;
/plugin/;
#include <dt-bindings/pinctrl/am33xx.h>
&{/chosen} {
overlays {
BONE-ST7580 = __TIMESTAMP__;
};
};
&ocp {
P9_24_pinmux { pinctrl-0 = <&P9_24_uart_pin>; }; /* UART TX*/
P9_26_pinmux { pinctrl-0 = <&P9_26_uart_pin>; }; /* UART RX*/
};
&bone_uart1 {
compatible = "st7580, st7580km";
status = "okay";
};
I have compiled the dts file to dtbo and placed the dtbo in /lib/firmware.我已经将 dts 文件编译为 dtbo 并将 dtbo 放在 /lib/firmware 中。
The kernel module source: kernel模块源码:
#include <asm/unaligned.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/serdev.h>
#define ST7580_DRIVER_NAME "st7580"
#define ST7580_DRIVER_VERSION "0.1.0"
#define ST7580_DEFAULT_BAUD_RATE 57600
#define ST7580_CHECKSUM_LENGTH 2
#define ST7580_MAX_DATA_LENGTH (3 + 255 + ST7580_CHECKSUM_LENGTH )
#define ST7580_TX_ACK_TIMEOUT msecs_to_jiffies(40)
static void st7580_write_wakeup(struct serdev_device *serdev)
{
dev_info(&serdev->dev, "\nst7580_write_wakeup: pull down RTS\n");
/* Pull down RTS */
serdev_device_set_tiocm(serdev, TIOCMBIS, TIOCM_RTS);
}
static int st7580_receive_buf(struct serdev_device *serdev,
const unsigned char *buf, size_t size)
{
dev_info(&serdev->dev, "\nst7580_receive_buf: Received %u bytes\n", size);
return serdev_controller_receive_buf(serdev, buf, size);
}
static const struct serdev_device_ops st7580_serdev_ops = {
.receive_buf = st7580_receive_buf, /* default */
.write_wakeup = st7580_write_wakeup,
};
static int st7580_probe(struct serdev_device *serdev)
{
int uart_flags;
int ret;
dev_info(&serdev->dev, "\nst7580_probe started...");
serdev_device_set_client_ops(serdev, &st7580_serdev_ops);
ret = devm_serdev_device_open(&serdev->dev, serdev);
if (ret) {
_dev_err(&serdev->dev, "unable to open the device\n");
return ret;
}
serdev_device_set_baudrate(serdev, ST7580_DEFAULT_BAUD_RATE);
serdev_device_set_flow_control(serdev, false);
ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
uart_flags = 0;
uart_flags &= ~PARENB;
uart_flags &= ~CSTOPB;
uart_flags &= ~CSIZE;
uart_flags |= CS8;
uart_flags &= ~CRTSCTS;
uart_flags |= CREAD | CLOCAL;
//uart_settings.c_iflag &= ~(IXON | IXOFF | IXANY);
//uart_settings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//uart_settings.c_iflag &= ~IGNBRK;
serdev_device_set_tiocm(serdev, TIOCMSET, uart_flags);
serdev_device_set_rts(serdev, 0);
serdev_device_set_tiocm(serdev, TIOCMSET, TIOCM_RTS);
dev_info(&serdev->dev, "\nDriver name is %s, loaded successsfully\n", ST7580_DRIVER_NAME);
return ret;
}
static const struct of_device_id st7580_of_match[] = {
{ .compatible = "stm7580,st7580" },
{ .compatible = "stm7580km,st7580km" },
{ .compatible = "st7580-fsk-psk,st7580" },
{ }
};
MODULE_DEVICE_TABLE(of, st7580_of_match);
static struct serdev_device_driver st7580_driver = {
.driver = {
.name = ST7580_DRIVER_NAME,
.of_match_table = st7580_of_match,
},
.probe = st7580_probe,
};
module_serdev_device_driver(st7580_driver);
I have also modified the /boot/uEnv.txt and added this line to load the DeviceTree overlay.我还修改了 /boot/uEnv.txt 并添加了这一行来加载 DeviceTree 覆盖。
optargs=quiet drm.debug=7 capemgr.enable_partno=BB-ST7580
When I reboot I expect that my driver will be loaded using which I can communicate to the modem from a userspace app.当我重新启动时,我希望我的驱动程序将被加载,我可以使用它从用户空间应用程序与调制解调器通信。 I have placed some debug messages in the code which I expect to see in the dmesg output like below:我在代码中放置了一些调试消息,我希望在 dmesg output 中看到这些消息,如下所示:
dev_info(&serdev->dev, "\nDriver name is %s, loaded successsfully\n", ST7580_DRIVER_NAME);
So far I do dont see any of the messages and am not sure if the kernel is using my driver for this peripheral.到目前为止,我没有看到任何消息,也不确定 kernel 是否正在使用我的驱动程序来处理这个外围设备。 Can any one tell me what I have missed or any errors?任何人都可以告诉我我遗漏了什么或有任何错误吗?
Step one is to hook up to the debug UART on the Beaglebone .第一步是连接到 Beaglebone 上的调试 UART 。 It gives you the necessary low level information to figure out what is happening during the U-Boot phase and early Kernel boot.它为您提供必要的低级信息,以了解在 U-Boot 阶段和早期 Kernel 引导期间发生的情况。
For embedded (Linux) work there is no excuse from hooking up to a UART.对于嵌入式 (Linux) 工作,没有理由不连接到 UART。 It's an essential tool.这是一个必不可少的工具。
Things to check for in this case is if you have more than one U-Boot in play (eMMC vs SD) and if you're working with the right one.在这种情况下要检查的事情是您是否有多个 U-Boot 正在运行(eMMC 与 SD)以及您是否正在使用正确的 U-Boot。 Also if there are any error messages from U-Boot, etc. It should be quite easy to tell from the UART output.此外,如果 U-Boot 等有任何错误消息。从 UART output 应该很容易判断。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.