arch: arm: add wsysinit

This commit is contained in:
Oliver Rohe
2020-09-09 11:21:34 +02:00
committed by Oleg Karfich
parent 288c4082a4
commit fcb81b750b
4 changed files with 354 additions and 0 deletions
@@ -26,6 +26,7 @@ CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_ARCH_OMAP3=y
CONFIG_ARCH_OMAP4=y
CONFIG_SOC_AM33XX=y
CONFIG_WAGO_SYSTEM_BASED_STARTUP=y
# CONFIG_SOC_OMAP3430 is not set
# CONFIG_SOC_TI81XX is not set
# CONFIG_MACH_OMAP3517EVM is not set
+5
View File
@@ -120,6 +120,11 @@ config ARCH_OMAP2PLUS
help
Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
config WAGO_SYSTEM_BASED_STARTUP
bool "WAGO System based startup code"
help
Enable WAGO System based startup code
config OMAP_INTERCONNECT_BARRIER
bool
select ARM_HEAVY_MB
+2
View File
@@ -226,3 +226,5 @@ targets += pm-asm-offsets.s
clean-files += pm-asm-offsets.h
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
obj-$(CONFIG_WAGO_SYSTEM_BASED_STARTUP) += wsysinit.o
+346
View File
@@ -0,0 +1,346 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* WAGO System Init Functions
*
* Copyright (C) 2014 WAGO Automation
*
* Author: Heinrich Toews
*/
#undef DEBUG
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/kobject.h>
#include <linux/fs.h>
#include <linux/timex.h>
#include <asm/mach-types.h>
#include <linux/delay.h>
#include "soc.h"
#define DEVICE_NAME "wsysinit-drv"
#define RESET_TIME_QUECTEL_UC20_G 200
struct wsysinit_settings {
bool dp_reset;
bool modem_reset;
int dp_gpio_rst;
int modem_gpio_rst;
bool dp_alow;
const char *tty_service;
const char *tty_rs232_485;
const char *modem;
int drvvbus_gpio;
const char *board_variant;
u32 adjtimex_tick;
u32 adjtimex_frequency;
};
static struct wsysinit_settings wsysinitset = { 0,};
static struct of_device_id wsysinit_dt_ids[] = {
{ .compatible = "wago,sysinit" },
{ }
};
MODULE_DEVICE_TABLE(of, wsysinit_dt_ids);
static int dp_trig_reset(struct wsysinit_settings *ps)
{
/* check if value is valid */
if (ps == NULL || !gpio_is_valid(ps->dp_gpio_rst))
return -EINVAL;
gpiod_set_value_cansleep(gpio_to_desc(ps->dp_gpio_rst), 1);
mdelay(100);
gpiod_set_value_cansleep(gpio_to_desc(ps->dp_gpio_rst), 0);
pr_info("DPx resetted (pin is active %s)!\n", ps->dp_alow ? "low" : "high");
return 0;
}
static int modem_reset(struct wsysinit_settings *ps)
{
if (ps == NULL || !gpio_is_valid(ps->modem_gpio_rst))
return -EINVAL;
gpiod_set_value_cansleep(gpio_to_desc(ps->modem_gpio_rst), 1);
mdelay(RESET_TIME_QUECTEL_UC20_G);
gpiod_set_value_cansleep(gpio_to_desc(ps->modem_gpio_rst), 0);
return 0;
}
static ssize_t dp_sysfs_trig_reset(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
u32 val = simple_strtoul(buf, NULL, 10);
/* check if value is valid */
if (val != 1)
return -EINVAL;
dp_trig_reset(&wsysinitset);
return count;
}
static ssize_t modem_sysfs_reset(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
u32 val = simple_strtoul(buf, NULL, 10);
if (val != 1)
return -EINVAL;
/* Return value omitted, because is of no value for the user of the command */
(void)modem_reset(&wsysinitset);
return count;
}
static int wsysinit_init_probe_dt(struct platform_device *pdev)
{
int ret;
struct device_node *np = pdev->dev.of_node;
enum of_gpio_flags flags;
struct __kernel_timex tmx = {0};
wsysinitset.dp_reset = of_property_read_bool(np, "dp,reset");
wsysinitset.dp_gpio_rst = of_get_named_gpio_flags(np, "dp,gpio-rst", 0, &flags);
if (wsysinitset.dp_gpio_rst == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (wsysinitset.dp_gpio_rst >= 0) {
int rqflags = 0;
wsysinitset.dp_alow = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
if (wsysinitset.dp_alow) /* FLAG_ACTIVE_LOW ?? */
rqflags |= GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
else
rqflags |= GPIOF_OUT_INIT_HIGH;
ret = devm_gpio_request_one(&pdev->dev, wsysinitset.dp_gpio_rst,
rqflags | GPIOF_EXPORT_DIR_FIXED, /* */
"Profibus Reset Pin");
if (ret < 0) {
dev_err(&pdev->dev, "failed to claim DP reset pin\n");
return ret;
}
if (wsysinitset.dp_reset)
dp_trig_reset(&wsysinitset);
} else if (wsysinitset.dp_reset) {
dev_err(&pdev->dev, "failed to find DP gpio reset signal!\n");
return -1;
}
wsysinitset.modem_reset = of_property_read_bool(np, "modem,reset");
wsysinitset.modem_gpio_rst = of_get_named_gpio_flags(np, "modem,gpio-rst", 0, &flags);
if (wsysinitset.modem_gpio_rst == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (wsysinitset.modem_gpio_rst >= 0) {
ret = devm_gpio_request_one(&pdev->dev, wsysinitset.modem_gpio_rst,
GPIOF_EXPORT_DIR_FIXED,
"Modem Reset Pin");
if (ret < 0) {
dev_err(&pdev->dev, "failed to claim modem reset pin\n");
return ret;
}
if (wsysinitset.modem_reset)
modem_reset(&wsysinitset);
/* devm_gpio_free(&pdev->dev, wsysinitset.dp_gpio_rst); */
} else if (wsysinitset.modem_reset) {
dev_err(&pdev->dev, "failed to find modem reset signal!\n");
return -1;
}
if (of_property_read_string(np, "modem,type", &wsysinitset.modem))
wsysinitset.modem = NULL;
if (of_property_read_string(np, "tty,service", &wsysinitset.tty_service))
wsysinitset.tty_service = NULL;
if (of_property_read_string(np, "tty,rs232-485", &wsysinitset.tty_rs232_485))
wsysinitset.tty_rs232_485 = NULL;
if (of_property_read_string(np, "board,variant", &wsysinitset.board_variant))
wsysinitset.board_variant = NULL;
if (!of_property_read_u32(np, "adjtimex,tick", &wsysinitset.adjtimex_tick)) {
tmx.modes |= ADJ_TICK;
tmx.tick = (__kernel_long_t) wsysinitset.adjtimex_tick;
}
if (!of_property_read_u32(np, "adjtimex,frequency", &wsysinitset.adjtimex_frequency)) {
tmx.modes |= ADJ_FREQUENCY;
tmx.freq = (__kernel_long_t) wsysinitset.adjtimex_frequency;
}
if (tmx.modes) {
do_adjtimex(&tmx);
pr_debug("%s: adjtimex: tick %u, frequency %u\n", __func__,
wsysinitset.adjtimex_tick, wsysinitset.adjtimex_frequency);
}
return 0;
}
/* WSYSINIT Specific Kernel Parameters */
char *__wsysinit_bootversion = NULL;
core_param(bootversion, __wsysinit_bootversion, charp, 0);
EXPORT_SYMBOL(__wsysinit_bootversion);
/* WSYSINIT SYSFS Init */
static dev_t wsysinit_sysfs_dev;
struct class* wsysinit_sysfs_class = NULL;
struct device* wsysinit_sysfs_device = NULL;
EXPORT_SYMBOL(wsysinit_sysfs_class);
EXPORT_SYMBOL(wsysinit_sysfs_device);
ssize_t wsysinit_sysfs_bootversion_show(struct device* dev, struct device_attribute* attr, char* buf)
{
if (__wsysinit_bootversion)
sprintf (buf, "%s\n", __wsysinit_bootversion);
else
sprintf (buf, "unknown\n");
return strlen(buf);
}
ssize_t wsysinit_sysfs_tty_service_show(struct device* dev, struct device_attribute* attr, char* buf)
{
if (wsysinitset.tty_service)
sprintf(buf, "%s\n", wsysinitset.tty_service);
else
sprintf(buf, "%s\n", "unknown");
return strlen(buf);
}
ssize_t wsysinit_sysfs_tty_rs232_485_show(struct device* dev, struct device_attribute* attr, char* buf)
{
if (wsysinitset.tty_rs232_485)
sprintf(buf, "%s\n", wsysinitset.tty_rs232_485);
else
sprintf(buf, "%s\n", "unknown");
return strlen(buf);
}
ssize_t wsysinit_sysfs_board_variant_show(struct device* dev, struct device_attribute* attr, char* buf)
{
if (wsysinitset.board_variant)
sprintf(buf, "%s\n", wsysinitset.board_variant);
else
sprintf(buf, "%s\n", "unknown");
return strlen(buf);
}
DEVICE_ATTR ( bootversion , 0444, wsysinit_sysfs_bootversion_show, NULL);
DEVICE_ATTR ( tty_service , 0444, wsysinit_sysfs_tty_service_show, NULL);
DEVICE_ATTR ( tty_rs232_485, 0444, wsysinit_sysfs_tty_rs232_485_show, NULL);
DEVICE_ATTR ( dp_trig_reset, 0200, NULL, dp_sysfs_trig_reset);
DEVICE_ATTR ( board_variant, 0444, wsysinit_sysfs_board_variant_show, NULL);
DEVICE_ATTR ( modem_reset, 0200, NULL, modem_sysfs_reset);
static void wsysinit_sysfs_init(void)
{
device_create_file(wsysinit_sysfs_device, &dev_attr_bootversion);
device_create_file(wsysinit_sysfs_device, &dev_attr_dp_trig_reset);
device_create_file(wsysinit_sysfs_device, &dev_attr_board_variant);
if (wsysinitset.modem)
device_create_file(wsysinit_sysfs_device, &dev_attr_modem_reset);
if (wsysinitset.tty_service)
device_create_file(wsysinit_sysfs_device, &dev_attr_tty_service);
if (wsysinitset.tty_rs232_485)
device_create_file(wsysinit_sysfs_device, &dev_attr_tty_rs232_485);
}
static int wsysinit_init_probe(struct platform_device *pdev)
{
int rc;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "WSYSINIT Init: No DT node found!\n");
return -1;
}
rc = wsysinit_init_probe_dt(pdev);
if (rc < 0) {
dev_err(&pdev->dev, "failed to probe DT parameters\n");
return rc;
}
wsysinit_sysfs_init();
pr_info("WAGO WSYSINIT Init: %s probed.\n", pdev->dev.of_node->name);
return 0;
}
static int wsysinit_init_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver wsysinit_init_driver = {
.probe = wsysinit_init_probe,
.remove = wsysinit_init_remove,
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(wsysinit_dt_ids),
},
};
static __init int wsysinit_init(void)
{
pr_info("WSYSINIT: create sysfs entries\n");
wsysinit_sysfs_class = class_create("wago");
if (IS_ERR(wsysinit_sysfs_class)) {
pr_err("%s: class_create: error %li\n",
__func__, PTR_ERR(wsysinit_sysfs_class));
unregister_chrdev_region(wsysinit_sysfs_dev, 1);
return -1;
}
wsysinit_sysfs_device = device_create (wsysinit_sysfs_class, NULL,
wsysinit_sysfs_dev, NULL, "system");
return platform_driver_register(&wsysinit_init_driver);
}
static __exit void wsysinit_exit(void)
{
platform_driver_unregister(&wsysinit_init_driver);
}
omap_postcore_initcall(wsysinit_init);
module_exit(wsysinit_exit);