summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-01-11 13:11:06 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2016-01-11 13:11:06 +0100
commitb9a2512aaa22086dc84db3f55a0d912b206c11e3 (patch)
tree38cfaccf38003f10032808354fce63d1b369c9e2 /drivers
parentb1ebbe76eb48b56ccd804636edcb5fb0b49da98a (diff)
parent0295088d53cd605aaf2a2accfd65c19c0f8a0cf0 (diff)
downloadbarebox-b9a2512aaa22086dc84db3f55a0d912b206c11e3.tar.gz
barebox-b9a2512aaa22086dc84db3f55a0d912b206c11e3.tar.xz
Merge branch 'for-next/misc'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/gpio_keys.c23
-rw-r--r--drivers/of/Kconfig7
-rw-r--r--drivers/of/barebox.c47
-rw-r--r--drivers/of/of_path.c123
-rw-r--r--drivers/pci/pci-imx6.c75
-rw-r--r--drivers/usb/imx/chipidea-imx.c3
6 files changed, 160 insertions, 118 deletions
diff --git a/drivers/input/gpio_keys.c b/drivers/input/gpio_keys.c
index d017594662..5b03fd76cb 100644
--- a/drivers/input/gpio_keys.c
+++ b/drivers/input/gpio_keys.c
@@ -21,6 +21,9 @@ struct gpio_key {
int active_low;
int previous_state;
+
+ int debounce_interval;
+ u64 debounce_start;
};
struct gpio_keys {
@@ -60,11 +63,17 @@ static void gpio_key_poller(struct poller_struct *poller)
gb = &gk->buttons[i];
val = gpio_get_value(gb->gpio);
- if (val != gb->previous_state && val != gb->active_low) {
- kfifo_put(gk->recv_fifo, (u_char*)&gb->code, sizeof(int));
- debug("pressed gpio(%d) as %d\n", gb->gpio, gb->code);
+ if (!is_timeout(gb->debounce_start, gb->debounce_interval * MSECOND))
+ continue;
+
+ if (val != gb->previous_state) {
+ gb->debounce_start = get_time_ns();
+ if (val != gb->active_low) {
+ kfifo_put(gk->recv_fifo, (u_char*)&gb->code, sizeof(int));
+ debug("pressed gpio(%d) as %d\n", gb->gpio, gb->code);
+ }
+ gb->previous_state = val;
}
- gb->previous_state = val;
}
}
@@ -111,6 +120,7 @@ static int gpio_keys_probe_pdata(struct gpio_keys *gk, struct device_d *dev)
gk->buttons[i].gpio = pdata->buttons[i].gpio;
gk->buttons[i].code = pdata->buttons[i].code;
gk->buttons[i].active_low = pdata->buttons[i].active_low;
+ gk->buttons[i].debounce_interval = 20;
}
return 0;
@@ -142,6 +152,11 @@ static int gpio_keys_probe_dt(struct gpio_keys *gk, struct device_d *dev)
if (ret)
return ret;
+ gk->buttons[i].debounce_interval = 20;
+
+ of_property_read_u32(npkey, "debounce-interval",
+ &gk->buttons[i].debounce_interval);
+
gk->buttons[i].code = keycode;
i++;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 90475cfbca..d0a62bda91 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -43,3 +43,10 @@ config OF_BAREBOX_DRIVERS
support for this feature. This currently allows to configure the
environment path from devicetree and to partition devices. See
Documentation/devicetree/bindings/barebox/ for more information.
+
+config OF_BAREBOX_ENV_IN_FS
+ depends on OF_BAREBOX_DRIVERS
+ bool "Allow environment to come from file"
+ help
+ Allow the devie tree configuration of the barebox environment path
+ to specify a file in filesystem, which will be mounted.
diff --git a/drivers/of/barebox.c b/drivers/of/barebox.c
index 1b3078eb47..125feef2cc 100644
--- a/drivers/of/barebox.c
+++ b/drivers/of/barebox.c
@@ -24,7 +24,46 @@
#include <malloc.h>
#include <partition.h>
#include <envfs.h>
-#include <linux/mtd/mtd.h>
+#include <fs.h>
+
+#define ENV_MNT_DIR "/boot" /* If env on filesystem, where to mount */
+
+/* If dev describes a file on a fs, mount the fs and change devpath to
+ * point to the file's path. Otherwise leave devpath alone. Does
+ * nothing in env in a file support isn't enabled. */
+static int environment_check_mount(struct device_d *dev, char **devpath)
+{
+ const char *filepath;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_OF_BAREBOX_ENV_IN_FS))
+ return 0;
+
+ ret = of_property_read_string(dev->device_node, "file-path", &filepath);
+ if (ret == -EINVAL) {
+ /* No file-path so just use device-path */
+ return 0;
+ } else if (ret) {
+ /* file-path property exists, but has error */
+ dev_err(dev, "Problem with file-path property\n");
+ return ret;
+ }
+
+ /* Get device env is on and mount it */
+ mkdir(ENV_MNT_DIR, 0777);
+ ret = mount(*devpath, "fat", ENV_MNT_DIR, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to load environment: mount %s failed (%d)\n",
+ *devpath, ret);
+ return ret;
+ }
+
+ /* Set env to be in a file on the now mounted device */
+ dev_dbg(dev, "Loading default env from %s on device %s\n",
+ filepath, *devpath);
+ *devpath = asprintf("%s/%s", ENV_MNT_DIR, filepath);
+ return 0;
+}
static int environment_probe(struct device_d *dev)
{
@@ -35,8 +74,12 @@ static int environment_probe(struct device_d *dev)
if (ret)
return ret;
- dev_info(dev, "setting default environment path to %s\n", path);
+ /* Do we need to mount a fs and find env there? */
+ ret = environment_check_mount(dev, &path);
+ if (ret)
+ return ret;
+ dev_dbg(dev, "Setting default environment path to %s\n", path);
default_environment_path_set(path);
return 0;
diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c
index 9016147db8..ed620f1755 100644
--- a/drivers/of/of_path.c
+++ b/drivers/of/of_path.c
@@ -23,16 +23,6 @@
#include <linux/mtd/mtd.h>
-struct of_path {
- struct cdev *cdev;
- struct device_d *dev;
-};
-
-struct of_path_type {
- const char *name;
- int (*parse)(struct of_path *op, const char *str);
-};
-
struct device_d *of_find_device_by_node_path(const char *path)
{
struct device_d *dev;
@@ -48,65 +38,6 @@ struct device_d *of_find_device_by_node_path(const char *path)
}
/**
- * of_path_type_partname - find a partition based on physical device and
- * partition name
- * @op: of_path context
- * @name: the partition name to find
- */
-static int of_path_type_partname(struct of_path *op, const char *name)
-{
- if (!op->dev)
- return -EINVAL;
-
- op->cdev = device_find_partition(op->dev, name);
- if (op->cdev) {
- pr_debug("%s: found part '%s'\n", __func__, name);
- return 0;
- } else {
- pr_debug("%s: cannot find part '%s'\n", __func__, name);
- return -ENODEV;
- }
-}
-
-static struct of_path_type of_path_types[] = {
- {
- .name = "partname",
- .parse = of_path_type_partname,
- },
-};
-
-static int of_path_parse_one(struct of_path *op, const char *str)
-{
- int i, ret;
- char *name, *desc;
-
- pr_debug("parsing: %s\n", str);
-
- name = xstrdup(str);
- desc = strchr(name, ':');
- if (!desc) {
- free(name);
- return -EINVAL;
- }
-
- *desc = 0;
- desc++;
-
- for (i = 0; i < ARRAY_SIZE(of_path_types); i++) {
- if (!strcmp(of_path_types[i].name, name)) {
- ret = of_path_types[i].parse(op, desc);
- goto out;
- }
- }
-
- ret = -EINVAL;
-out:
- free(name);
-
- return ret;
-}
-
-/**
* __of_find_path
*
* @node: The node to find the cdev for, can be the device or a
@@ -119,36 +50,32 @@ out:
*/
static int __of_find_path(struct device_node *node, const char *part, char **outpath, unsigned flags)
{
- struct of_path op;
+ struct device_d *dev;
+ struct cdev *cdev;
bool add_bb = false;
- int ret;
- op.dev = of_find_device_by_node_path(node->full_name);
- if (!op.dev) {
- op.dev = of_find_device_by_node_path(node->parent->full_name);
- if (!op.dev)
+ dev = of_find_device_by_node_path(node->full_name);
+ if (!dev) {
+ dev = of_find_device_by_node_path(node->parent->full_name);
+ if (!dev)
return -ENODEV;
}
- device_detect(op.dev);
+ device_detect(dev);
- if (part) {
- /* Find a partition inside op.dev */
- ret = of_path_parse_one(&op, part);
- if (ret)
- return ret;
- } else {
- /* node points directly to device */
- op.cdev = cdev_by_device_node(node);
- if (!op.cdev)
- return -ENOENT;
- }
+ if (part)
+ cdev = device_find_partition(dev, part);
+ else
+ cdev = cdev_by_device_node(node);
- if ((flags & OF_FIND_PATH_FLAGS_BB) && op.cdev->mtd &&
- mtd_can_have_bb(op.cdev->mtd))
+ if (!cdev)
+ return -ENOENT;
+
+ if ((flags & OF_FIND_PATH_FLAGS_BB) && cdev->mtd &&
+ mtd_can_have_bb(cdev->mtd))
add_bb = true;
- *outpath = asprintf("/dev/%s%s", op.cdev->name, add_bb ? ".bb" : "");
+ *outpath = asprintf("/dev/%s%s", cdev->name, add_bb ? ".bb" : "");
return 0;
}
@@ -198,8 +125,8 @@ int of_find_path(struct device_node *node, const char *propname, char **outpath,
{
struct device_node *rnode;
const char *path;
- const char *part;
- int ret;
+ const char *part = NULL;
+ const char partnamestr[] = "partname:";
path = of_get_property(node, propname, NULL);
if (!path)
@@ -209,9 +136,15 @@ int of_find_path(struct device_node *node, const char *propname, char **outpath,
if (!rnode)
return -ENODEV;
- ret = of_property_read_string_index(node, propname, 1, &part);
- if (ret)
- part = NULL;
+ of_property_read_string_index(node, propname, 1, &part);
+ if (part) {
+ if (!strncmp(part, partnamestr, sizeof(partnamestr) - 1)) {
+ part += sizeof(partnamestr) - 1;
+ } else {
+ pr_err("Invalid device-path: %s\n", part);
+ return -EINVAL;
+ }
+ }
return __of_find_path(rnode, part, outpath, flags);
}
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index eaa5f0ef58..d32bd2b4ce 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -13,6 +13,7 @@
#include <common.h>
#include <clock.h>
+#include <abort.h>
#include <malloc.h>
#include <io.h>
#include <init.h>
@@ -51,6 +52,8 @@ struct imx6_pcie {
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
+#define PCIE_RC_LCSR 0x80
+
/* PCIe Port Logic registers (memory-mapped) */
#define PL_OFFSET 0x700
#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
@@ -235,7 +238,10 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
val = readl(pp->dbi_base + PCIE_PL_PFLR);
val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
val |= PCIE_PL_PFLR_FORCE_LINK;
+
+ data_abort_mask();
writel(val, pp->dbi_base + PCIE_PL_PFLR);
+ data_abort_unmask();
gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
@@ -360,13 +366,29 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp)
}
}
+static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp)
+{
+ uint32_t tmp;
+ uint64_t start = get_time_ns();
+
+ while (!is_timeout(start, SECOND)) {
+ tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
+ /* Test if the speed change finished. */
+ if (!(tmp & PORT_LOGIC_SPEED_CHANGE))
+ return 0;
+ }
+
+ dev_err(pp->dev, "Speed change timeout\n");
+ return -EINVAL;
+}
+
+
static int imx6_pcie_start_link(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
uint32_t tmp;
int ret;
u32 gpr12;
- u64 start;
/*
* Force Gen1 operation when starting the link. In case the link is
@@ -401,28 +423,22 @@ static int imx6_pcie_start_link(struct pcie_port *pp)
tmp |= PORT_LOGIC_SPEED_CHANGE;
writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
- start = get_time_ns();
- while (!is_timeout(start, SECOND)) {
- tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
- /* Test if the speed change finished. */
- if (!(tmp & PORT_LOGIC_SPEED_CHANGE))
- break;
+ ret = imx6_pcie_wait_for_speed_change(pp);
+ if (ret) {
+ dev_err(pp->dev, "Failed to bring link up!\n");
+ return ret;
}
/* Make sure link training is finished as well! */
- if (tmp & PORT_LOGIC_SPEED_CHANGE)
- ret = -EINVAL;
- else
- ret = imx6_pcie_wait_for_link(pp);
-
+ ret = imx6_pcie_wait_for_link(pp);
if (ret) {
dev_err(pp->dev, "Failed to bring link up!\n");
- } else {
- tmp = readl(pp->dbi_base + 0x80);
- dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
+ return ret;
}
- return ret;
+ tmp = readl(pp->dbi_base + PCIE_RC_LCSR);
+ dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
+ return 0;
}
static void imx6_pcie_host_init(struct pcie_port *pp)
@@ -592,9 +608,35 @@ static int __init imx6_pcie_probe(struct device_d *dev)
if (ret < 0)
return ret;
+ dev->priv = imx6_pcie;
+
return 0;
}
+static void imx6_pcie_remove(struct device_d *dev)
+{
+ struct imx6_pcie *imx6_pcie = dev->priv;
+ u32 val;
+
+ val = readl(imx6_pcie->pp.dbi_base + PCIE_PL_PFLR);
+ val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
+ val |= PCIE_PL_PFLR_FORCE_LINK;
+ data_abort_mask();
+ writel(val, imx6_pcie->pp.dbi_base + PCIE_PL_PFLR);
+ data_abort_unmask();
+
+ val = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+ val &= ~IMX6Q_GPR12_PCIE_CTL_2;
+ writel(val, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+
+ val = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+ val |= IMX6Q_GPR1_PCIE_TEST_PD;
+ writel(val, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+
+ val &= ~IMX6Q_GPR1_PCIE_REF_CLK_EN;
+ writel(val, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+}
+
static struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx6q-pcie", },
{},
@@ -604,6 +646,7 @@ static struct driver_d imx6_pcie_driver = {
.name = "imx6-pcie",
.of_compatible = DRV_OF_COMPAT(imx6_pcie_of_match),
.probe = imx6_pcie_probe,
+ .remove = imx6_pcie_remove,
};
device_platform_driver(imx6_pcie_driver);
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index ae307183bc..a1c36cf644 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -242,7 +242,8 @@ static int imx_chipidea_probe(struct device_d *dev)
ci->vbus = regulator_get(dev, "vbus");
- regulator_enable(ci->vbus);
+ if (!IS_ERR(ci->vbus))
+ regulator_enable(ci->vbus);
base = dev_request_mem_region(dev, 0);
if (IS_ERR(base))