arch: arm: add wsysinit
This commit is contained in:
committed by
Oleg Karfich
parent
288c4082a4
commit
fcb81b750b
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user