mach-omap2: support existing userspace tools

This is implemented as a platform device and instantiated using DT.

Signed-off-by: Jan Luebbe <jluebbe@debian.org>
master
Jan Luebbe 8 years ago committed by Harald Welte
parent 006dbf34cd
commit 09476e9d9b

@ -232,6 +232,7 @@ obj-$(CONFIG_SOC_OMAP2420) += msdi.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o pdata-quirks.o
obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o
obj-$(CONFIG_SOC_AM33XX) += board-sob-odu.o
# Platform specific device init code

@ -0,0 +1,208 @@
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/irqdomain.h>
#include <linux/gpio.h>
#include <linux/nvmem-consumer.h>
#include <linux/crc32.h>
#include <asm/mach/arch.h>
#include "common.h"
#include "sob_odu_eeprom.h"
static ssize_t board_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct sob_odu_eeprom *soe = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", soe->model);
}
static ssize_t serial_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct sob_odu_eeprom *soe = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", soe->serial);
}
static ssize_t hw_options_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct sob_odu_eeprom *soe = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", soe->hw_options);
}
static ssize_t mfg_date_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct sob_odu_eeprom *soe = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", soe->manuf_date);
}
static const DEVICE_ATTR(board_version, 0444, board_version_show, NULL);
static const DEVICE_ATTR(serial_number, 0444, serial_number_show, NULL);
static const DEVICE_ATTR(hw_options, 0444, hw_options_show, NULL);
static const DEVICE_ATTR(mfg_date, 0444, mfg_date_show, NULL);
static const struct attribute *sobodu_attrs[] = {
&dev_attr_board_version.attr,
&dev_attr_serial_number.attr,
&dev_attr_hw_options.attr,
&dev_attr_mfg_date.attr,
NULL,
};
static const struct attribute_group sobodu_attr_group = {
.attrs = (struct attribute **) sobodu_attrs,
};
#define G2I(bank, io) ((bank)*32 + (io))
static const struct gpio gpio_exp[] = {
{ G2I(1,16), GPIOF_OUT_INIT_HIGH, "!ais_off" },
{ G2I(1,20), GPIOF_IN, "ais_rx_ind" },
{ G2I(1,24), GPIOF_IN, "ais_status_ind" },
{ G2I(0,27), GPIOF_IN, "ais_error_ind" },
{ G2I(0,23), GPIOF_IN, "ais_powerok_ind" },
{ G2I(0,22), GPIOF_IN, "!mdm1_pwr_ind" },
{ G2I(0,26), GPIOF_OUT_INIT_LOW, "mdm1_rst" },
{ G2I(1,27), GPIOF_OUT_INIT_HIGH, "mdm1_on" },
{ G2I(1,26), GPIOF_OUT_INIT_HIGH, "mdm_ldo_en" },
{ G2I(1,25), GPIOF_IN, "!mdm2_pwr_ind" },
{ G2I(1,23), GPIOF_OUT_INIT_LOW, "mdm2_rst" },
{ G2I(1,18), GPIOF_OUT_INIT_HIGH, "mdm2_on" },
/* G2I(1,19) is now registered by the at24 driver */
{ G2I(3,17), GPIOF_IN, "gnss_fix" },
/* G2I(3,19) is now registered to the PPS core */
{ G2I(3,18), GPIOF_OUT_INIT_HIGH, "!gnss_rst" },
{ G2I(1,22), GPIOF_IN, "adsb_frame_ind" },
{ G2I(1,21), GPIOF_OUT_INIT_HIGH, "!adsb_rst" },
{ G2I(3,8), GPIOF_IN, "acc_int1" },
{ G2I(3,7), GPIOF_IN, "acc_int2" },
{ G2I(1,30), GPIOF_OUT_INIT_HIGH, "!hub_reset" },
};
static int sob_odu_probe(struct platform_device *pdev)
{
struct sob_odu_eeprom *soe;
struct nvmem_device *nvmem;
uint32_t crc32_comp;
int i, rc;
soe = devm_kzalloc(&pdev->dev, sizeof(struct sob_odu_eeprom),
GFP_KERNEL);
if (!soe)
return -ENOMEM;
nvmem = devm_nvmem_device_get(&pdev->dev, "baseboard");
if (IS_ERR(nvmem)) {
if (PTR_ERR(nvmem) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get nvmem\n");
return PTR_ERR(nvmem);
}
rc = nvmem_device_read(nvmem, 0, sizeof(*soe), soe);
if (rc < sizeof(*soe)) {
dev_err(&pdev->dev, "failed to read nvmem\n");
return -EINVAL;
}
if (soe->magic != SOBJB_EE_MAGIC || soe->version != SOBJB_EE_VERSION) {
dev_err(&pdev->dev, "EEPROM magic/version wrong\n");
return -EINVAL;
}
crc32_comp = crc32_le(0xffffffff, (void *)soe + 8, sizeof(*soe)-8);
if (soe->crc32 != crc32_comp) {
dev_err(&pdev->dev, "EEPROM CRC32 mismatch (eeprom=0x%08x, computed=0x%08x)\n",
soe->crc32, crc32_comp);
return -EINVAL;
}
dev_info(&pdev->dev, "SOB-ODU board v%u, serial number %u, mfg %u, hw_options=0x%08x\n",
soe->model, soe->serial, soe->manuf_date, soe->hw_options);
/* FIXME: export the board version via sysfs */
/* FIXME: configure the MAC addresses of the wlan adapters */
/* export all of the GPIOs from the above array */
rc = gpio_request_array(gpio_exp, ARRAY_SIZE(gpio_exp));
if (rc) {
dev_err(&pdev->dev, "failed to request GPIOs\n");
return rc;
}
for (i = 0; i < ARRAY_SIZE(gpio_exp); i++) {
bool chg_dir_perm = false;
char label[64];
/* this is the only one where the direction may be
* changed */
if (gpio_exp[i].gpio == G2I(3,7))
chg_dir_perm = true;
/* export it to sysfs */
rc = gpio_export(gpio_exp[i].gpio, chg_dir_perm);
if (rc)
dev_warn(&pdev->dev, "unable to export GPIO %u\n", gpio_exp[i].gpio);
/* set active-low attribute to invert logic */
if (gpio_exp[i].label[0] == '!') {
gpio_sysfs_set_active_low(gpio_exp[i].gpio, true);
/* skip initial '!' of negated signals */
snprintf(label, sizeof(label)-1, "gpio_%s", gpio_exp[i].label + 1);
} else
snprintf(label, sizeof(label)-1, "gpio_%s", gpio_exp[i].label);
/* generate symlink to /sys/devices/platform/sob-odu.0 */
rc = gpio_export_link(&pdev->dev, label,
gpio_exp[i].gpio);
if (rc)
dev_warn(&pdev->dev, "unable to symlink GPIO %u\n", gpio_exp[i].gpio);
}
switch (soe->model) {
case SOB_ODU_V3: {
int gpio37 = G2I(3,7);
/* GPIO_3_7 is AIS VBUS enable, not ACC_INT2 */
sysfs_remove_link(&pdev->dev.kobj, "acc_int2");
gpio_unexport(gpio37);
gpio_free(gpio37);
gpio_request(gpio37, "ais_vbus_enable");
gpio_direction_output(gpio37, true);
gpio_export(gpio37, false);
gpio_sysfs_set_active_low(gpio37, false);
gpio_export_link(&pdev->dev, "gpio_ais_vbus_enable",
gpio37);
break;}
}
platform_set_drvdata(pdev, soe);
if (sysfs_create_group(&pdev->dev.kobj, &sobodu_attr_group))
dev_err(&pdev->dev, "failed to create sysfs group\n");
return 0;
}
static const struct of_device_id sob_odu_dt_ids[] = {
{ .compatible = "sysmocom,sob-odu-platform", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sob_odu_dt_ids);
static struct platform_driver sob_odu_driver = {
.probe = sob_odu_probe,
.driver = {
.name = "sob-odu-platform",
.of_match_table = sob_odu_dt_ids,
},
};
module_platform_driver(sob_odu_driver);

@ -0,0 +1,28 @@
#pragma once
#define MAC_ADDR_LEN 6
#define SOBJB_EE_MAGIC 0x50b0d0ee
#define SOBJB_EE_VERSION 1
#define SOB_ODU_V1 1
#define SOB_ODU_V2 2
#define SOB_ODU_V3 3
struct sob_odu_eeprom {
uint32_t magic; /* SOBJB_EE_MAGIC */
uint32_t crc32; /* crc32_le */
uint16_t len; /* sizeof(struct sob_odu_eeprom) */
uint8_t version; /* SOBJB_EE_VERSION */
uint8_t model; /* SOB_ODU_V* */
uint32_t serial;
uint32_t manuf_date;
uint32_t hw_options;
uint8_t mac_eth0[MAC_ADDR_LEN];
uint8_t mac_eth1[MAC_ADDR_LEN];
uint8_t mac_wlan0[MAC_ADDR_LEN];
uint8_t mac_wlan1[MAC_ADDR_LEN];
} __attribute__ ((packed));
Loading…
Cancel
Save