summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clocksource/Kconfig4
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/input/gpio_keys.c23
-rw-r--r--drivers/mci/Kconfig6
-rw-r--r--drivers/mci/Makefile2
-rw-r--r--drivers/mtd/nand/nand_base.c128
-rw-r--r--drivers/mtd/nand/nand_mxs.c42
-rw-r--r--drivers/of/Kconfig7
-rw-r--r--drivers/of/barebox.c47
-rw-r--r--drivers/of/of_path.c132
-rw-r--r--drivers/pci/pci-imx6.c75
-rw-r--r--drivers/regulator/Kconfig4
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/reset/core.c1
-rw-r--r--drivers/rtc/Kconfig3
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c11
-rw-r--r--drivers/rtc/rtc-abracon.c126
-rw-r--r--drivers/rtc/rtc-ds1307.c94
-rw-r--r--drivers/rtc/rtc-lib.c2
-rw-r--r--drivers/usb/imx/chipidea-imx.c3
-rw-r--r--drivers/video/Kconfig8
-rw-r--r--drivers/video/Makefile2
25 files changed, 594 insertions, 139 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 598edc9a81..3fb09fbec4 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -6,9 +6,9 @@ config ARM_SMP_TWD
bool
depends on ARM && CPU_V7
-config CLOCKSOURCE_BCM2835
+config CLOCKSOURCE_BCM283X
bool
- depends on ARCH_BCM2835
+ depends on ARCH_BCM283X
config CLOCKSOURCE_CLPS711X
bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f5f5141a3d..4eb1656ee0 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_AMBA_SP804) += amba-sp804.o
obj-$(CONFIG_ARM_SMP_TWD) += arm_smp_twd.o
-obj-$(CONFIG_CLOCKSOURCE_BCM2835) += bcm2835.o
+obj-$(CONFIG_CLOCKSOURCE_BCM283X) += bcm2835.o
obj-$(CONFIG_CLOCKSOURCE_CLPS711X) += clps711x.o
obj-$(CONFIG_CLOCKSOURCE_DIGIC) += digic.o
obj-$(CONFIG_CLOCKSOURCE_MVEBU) += mvebu.o
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9cb22613dd..d839d7a426 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -21,9 +21,9 @@ config GPIO_74164
shift registers. This driver can be used to provide access
to more gpio outputs.
-config GPIO_BCM2835
- bool "GPIO support for BCM2835"
- depends on ARCH_BCM2835
+config GPIO_BCM283X
+ bool "GPIO support for BCM283X"
+ depends on ARCH_BCM283X
config GPIO_CLPS711X
bool "GPIO support for CLPS711X"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index f39e8da6e1..8767eed1e8 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_74164) += gpio-74164.o
obj-$(CONFIG_MACH_MIPS_ATH79) += gpio-ath79.o
-obj-$(CONFIG_GPIO_BCM2835) += gpio-bcm2835.o
+obj-$(CONFIG_GPIO_BCM283X) += gpio-bcm2835.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_DIGIC) += gpio-digic.o
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/mci/Kconfig b/drivers/mci/Kconfig
index ebd8da9591..0f3504c735 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -62,9 +62,9 @@ config MCI_S3C
Enable this entry to add support to read and write SD cards on a
Samsung S3C24xx based system.
-config MCI_BCM2835
- bool "MCI support for BCM2835"
- depends on ARCH_BCM2835
+config MCI_BCM283X
+ bool "MCI support for BCM283X"
+ depends on ARCH_BCM283X
config MCI_IMX
bool "i.MX"
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 1e8443c1af..88ec456aa3 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_MCI) += mci-core.o
obj-$(CONFIG_MCI_ATMEL) += atmel_mci.o
-obj-$(CONFIG_MCI_BCM2835) += mci-bcm2835.o
+obj-$(CONFIG_MCI_BCM283X) += mci-bcm2835.o
obj-$(CONFIG_MCI_IMX) += imx.o
obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o
obj-$(CONFIG_MCI_MXS) += mxs.o
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ca48f59de1..554d3d2f96 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -907,6 +907,134 @@ out:
EXPORT_SYMBOL(nand_lock);
/**
+ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
+ * @buf: buffer to test
+ * @len: buffer length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a buffer contains only 0xff, which means the underlying region
+ * has been erased and is ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region is not erased.
+ * Note: The logic of this function has been extracted from the memweight
+ * implementation, except that nand_check_erased_buf function exit before
+ * testing the whole buffer if the number of bitflips exceed the
+ * bitflips_threshold value.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold.
+ */
+static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
+{
+ const unsigned char *bitmap = buf;
+ int bitflips = 0;
+ int weight;
+
+ for (; len && ((uintptr_t)bitmap) % sizeof(long);
+ len--, bitmap++) {
+ weight = hweight8(*bitmap);
+ bitflips += BITS_PER_BYTE - weight;
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ for (; len >= sizeof(long);
+ len -= sizeof(long), bitmap += sizeof(long)) {
+ weight = hweight_long(*((unsigned long *)bitmap));
+ bitflips += BITS_PER_LONG - weight;
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ for (; len > 0; len--, bitmap++) {
+ weight = hweight8(*bitmap);
+ bitflips += BITS_PER_BYTE - weight;
+ if (unlikely(bitflips > bitflips_threshold))
+ return -EBADMSG;
+ }
+
+ return bitflips;
+}
+
+/**
+ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
+ * 0xff data
+ * @data: data buffer to test
+ * @datalen: data length
+ * @ecc: ECC buffer
+ * @ecclen: ECC length
+ * @extraoob: extra OOB buffer
+ * @extraooblen: extra OOB length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a data buffer and its associated ECC and OOB data contains only
+ * 0xff pattern, which means the underlying region has been erased and is
+ * ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region as not erased.
+ *
+ * Note:
+ * 1/ ECC algorithms are working on pre-defined block sizes which are usually
+ * different from the NAND page size. When fixing bitflips, ECC engines will
+ * report the number of errors per chunk, and the NAND core infrastructure
+ * expect you to return the maximum number of bitflips for the whole page.
+ * This is why you should always use this function on a single chunk and
+ * not on the whole page. After checking each chunk you should update your
+ * max_bitflips value accordingly.
+ * 2/ When checking for bitflips in erased pages you should not only check
+ * the payload data but also their associated ECC data, because a user might
+ * have programmed almost all bits to 1 but a few. In this case, we
+ * shouldn't consider the chunk as erased, and checking ECC bytes prevent
+ * this case.
+ * 3/ The extraoob argument is optional, and should be used if some of your OOB
+ * data are protected by the ECC engine.
+ * It could also be used if you support subpages and want to attach some
+ * extra OOB data to an ECC chunk.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold. In case of success, the passed buffers are filled with 0xff.
+ */
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+ void *ecc, int ecclen,
+ void *extraoob, int extraooblen,
+ int bitflips_threshold)
+{
+ int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
+
+ data_bitflips = nand_check_erased_buf(data, datalen,
+ bitflips_threshold);
+ if (data_bitflips < 0)
+ return data_bitflips;
+
+ bitflips_threshold -= data_bitflips;
+
+ ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
+ if (ecc_bitflips < 0)
+ return ecc_bitflips;
+
+ bitflips_threshold -= ecc_bitflips;
+
+ extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
+ bitflips_threshold);
+ if (extraoob_bitflips < 0)
+ return extraoob_bitflips;
+
+ if (data_bitflips)
+ memset(data, 0xff, datalen);
+
+ if (ecc_bitflips)
+ memset(ecc, 0xff, ecclen);
+
+ if (extraoob_bitflips)
+ memset(extraoob, 0xff, extraooblen);
+
+ return data_bitflips + ecc_bitflips + extraoob_bitflips;
+}
+EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
+
+/**
* nand_read_page_raw - [INTERN] read raw page data without ecc
* @mtd: mtd info structure
* @chip: nand chip info structure
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index b3767e6cbe..7635e2a418 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -737,6 +737,8 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
/* Read DMA completed, now do the mark swapping. */
mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf);
+ memcpy(buf, nand_info->data_buf, mtd->writesize);
+
/* Loop over status bytes, accumulating ECC status. */
status = nand_info->oob_buf + mxs_nand_aux_status_offset();
for (i = 0; i < mxs_nand_ecc_chunk_cnt(mtd->writesize); i++) {
@@ -747,6 +749,44 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
continue;
if (status[i] == 0xfe) {
+ int flips;
+
+ /*
+ * The ECC hardware has an uncorrectable ECC status
+ * code in case we have bitflips in an erased page. As
+ * nothing was written into this subpage the ECC is
+ * obviously wrong and we can not trust it. We assume
+ * at this point that we are reading an erased page and
+ * try to correct the bitflips in buffer up to
+ * ecc_strength bitflips. If this is a page with random
+ * data, we exceed this number of bitflips and have a
+ * ECC failure. Otherwise we use the corrected buffer.
+ */
+ if (i == 0) {
+ /* The first block includes metadata */
+ flips = nand_check_erased_ecc_chunk(
+ buf + i * MXS_NAND_CHUNK_DATA_CHUNK_SIZE,
+ MXS_NAND_CHUNK_DATA_CHUNK_SIZE,
+ NULL, 0,
+ nand_info->oob_buf,
+ MXS_NAND_METADATA_SIZE,
+ mtd->ecc_strength);
+ } else {
+ flips = nand_check_erased_ecc_chunk(
+ buf + i * MXS_NAND_CHUNK_DATA_CHUNK_SIZE,
+ MXS_NAND_CHUNK_DATA_CHUNK_SIZE,
+ NULL, 0,
+ NULL, 0,
+ mtd->ecc_strength);
+ }
+
+ if (flips > 0) {
+ max_bitflips = max_t(unsigned int,
+ max_bitflips, flips);
+ corrected += flips;
+ continue;
+ }
+
failed++;
continue;
}
@@ -772,8 +812,6 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
nand->oob_poi[0] = nand_info->oob_buf[0];
- memcpy(buf, nand_info->data_buf, mtd->writesize);
-
ret = 0;
rtn:
mxs_nand_return_dma_descs(nand_info);
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 6903905259..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,102 +38,44 @@ 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
+ * __of_find_path
+ *
+ * @node: The node to find the cdev for, can be the device or a
+ * partition in the device
+ * @part: Optionally, a description of a parition of @node. See of_find_path
+ * @outpath: if this function returns 0 outpath will contain the path belonging
+ * to the input path description. Must be freed with free().
+ * @flags: use OF_FIND_PATH_FLAGS_BB to return the .bb device if available
+ *
*/
-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)
+static int __of_find_path(struct device_node *node, const char *part, char **outpath, unsigned flags)
{
- 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;
-}
-
-static int __of_find_path(struct device_node *node, const char *propname, char **outpath, unsigned flags)
-{
- struct of_path op = {};
- const char *str;
+ struct device_d *dev;
+ struct cdev *cdev;
bool add_bb = false;
- int i, 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);
-
- op.cdev = cdev_by_device_node(node);
+ device_detect(dev);
- i = 1;
+ if (part)
+ cdev = device_find_partition(dev, part);
+ else
+ cdev = cdev_by_device_node(node);
- while (propname) {
- ret = of_property_read_string_index(node, propname, i++, &str);
- if (ret)
- break;
-
- ret = of_path_parse_one(&op, str);
- if (ret)
- return ret;
- }
-
- if (!op.cdev)
+ if (!cdev)
return -ENOENT;
- if ((flags & OF_FIND_PATH_FLAGS_BB) && op.cdev->mtd &&
- mtd_can_have_bb(op.cdev->mtd))
+ 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;
}
@@ -193,6 +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 = NULL;
+ const char partnamestr[] = "partname:";
path = of_get_property(node, propname, NULL);
if (!path)
@@ -202,5 +136,15 @@ int of_find_path(struct device_node *node, const char *propname, char **outpath,
if (!rnode)
return -ENODEV;
- return __of_find_path(rnode, propname, outpath, flags);
+ 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/regulator/Kconfig b/drivers/regulator/Kconfig
index 05c3f48980..4b4125254f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -11,9 +11,9 @@ config REGULATOR_FIXED
This enables a simple fixed regulator. It is used for regulators
which are not software controllable or controllable via gpio.
-config REGULATOR_BCM2835
+config REGULATOR_BCM283X
bool
- depends on ARCH_BCM2835
+ depends on ARCH_BCM283X
default y
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d663c16b1a..a8dd9bd055 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_REGULATOR) += core.o
obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
-obj-$(CONFIG_REGULATOR_BCM2835) += bcm2835.o
+obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 0f900a92d0..59f75ca475 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -190,6 +190,7 @@ struct reset_control *of_reset_control_get(struct device_node *node,
rstc->rcdev = rcdev;
rstc->id = rstc_id;
+ rstc->gpio = -ENODEV;
return rstc;
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 191ad97fb8..7d181949ee 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -33,6 +33,9 @@ config RTC_DRV_DS1307
registers may add features such as NVRAM, a trickle charger for
the RTC/NVRAM backup power, and alarms.
+config RTC_DRV_ABRACON
+ tristate "Abracon RTCs"
+
endif # I2C
config RTC_DRV_JZ4740
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1cc9bb8b4b..68741c26a1 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_RTC_CLASS) += class.o
# Keep the list ordered.
+obj-$(CONFIG_RTC_DRV_ABRACON) += rtc-abracon.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 356707be2f..8b047a638d 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -46,7 +46,16 @@ EXPORT_SYMBOL(rtc_read_time);
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
- return rtc->ops->set_time(rtc, tm);
+ struct rtc_time time;
+ unsigned long secs;
+
+ if (rtc_valid_tm(tm))
+ return -EINVAL;
+
+ rtc_tm_to_time(tm, &secs);
+ rtc_time_to_tm(secs, &time);
+
+ return rtc->ops->set_time(rtc, &time);
}
EXPORT_SYMBOL(rtc_set_time);
diff --git a/drivers/rtc/rtc-abracon.c b/drivers/rtc/rtc-abracon.c
new file mode 100644
index 0000000000..b3af990b9c
--- /dev/null
+++ b/drivers/rtc/rtc-abracon.c
@@ -0,0 +1,126 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <i2c/i2c.h>
+#include <rtc.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+struct abracon {
+ struct rtc_device rtc;
+ struct i2c_client *client;
+};
+
+static inline struct abracon *to_abracon_priv(struct rtc_device *rtcdev)
+{
+ return container_of(rtcdev, struct abracon, rtc);
+}
+
+static int abracon_get_time(struct rtc_device *rtcdev, struct rtc_time *t)
+{
+ struct abracon *abracon = to_abracon_priv(rtcdev);
+ struct i2c_client *client = abracon->client;
+ u8 cp[7] = {};
+ u8 reg = 8;
+ struct i2c_msg msg[2] = {};
+ int ret;
+
+ msg[0].addr = client->addr;
+ msg[0].buf = &reg;
+ msg[0].len = 1;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = cp;
+ msg[1].len = 7;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret != 2)
+ return -EIO;
+
+ t->tm_sec = bcd2bin(cp[0]);
+ t->tm_min = bcd2bin(cp[1]);
+ t->tm_hour = bcd2bin(cp[2]);
+ t->tm_mday = bcd2bin(cp[3]);
+ t->tm_wday = bcd2bin(cp[4]);
+ t->tm_mon = bcd2bin(cp[5]);
+ t->tm_year = bcd2bin(cp[6]) + 100;
+
+ return 0;
+}
+
+static int abracon_set_time(struct rtc_device *rtcdev, struct rtc_time *t)
+{
+ struct abracon *abracon = to_abracon_priv(rtcdev);
+ struct i2c_client *client = abracon->client;
+ u8 cp[8] = {};
+ int ret;
+
+ cp[0] = 8;
+ cp[1] = bin2bcd(t->tm_sec);
+ cp[2] = bin2bcd(t->tm_min);
+ cp[3] = bin2bcd(t->tm_hour);
+ cp[4] = bin2bcd(t->tm_mday);
+ cp[5] = bin2bcd(t->tm_wday);
+ cp[6] = bin2bcd(t->tm_mon);
+ cp[7] = bin2bcd(t->tm_year - 100);
+
+ ret = i2c_master_send(client, cp, 8);
+ if (ret != 8)
+ return -EIO;
+
+ return 0;
+}
+
+static const struct rtc_class_ops ds13xx_rtc_ops = {
+ .read_time = abracon_get_time,
+ .set_time = abracon_set_time,
+};
+
+static int abracon_probe(struct device_d *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct abracon *abracon;
+ int ret;
+
+ abracon = xzalloc(sizeof(*abracon));
+
+ abracon->client = client;
+
+ abracon->rtc.ops = &ds13xx_rtc_ops;
+ abracon->rtc.dev = dev;
+
+ ret = rtc_register(&abracon->rtc);
+
+ return ret;
+};
+
+static struct platform_device_id abracon_id[] = {
+ { "ab-rtcmc-32.768khz-eoz9-s3", 0 },
+ { }
+};
+
+static struct driver_d abracon_driver = {
+ .name = "rtc-abracon",
+ .probe = abracon_probe,
+ .id_table = abracon_id,
+};
+
+static int __init abracon_init(void)
+{
+ return i2c_driver_register(&abracon_driver);
+}
+device_initcall(abracon_init); \ No newline at end of file
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index d78faa892d..e2d561b96f 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -17,6 +17,7 @@
#include <init.h>
#include <driver.h>
#include <xfuncs.h>
+#include <malloc.h>
#include <errno.h>
#include <i2c/i2c.h>
#include <rtc.h>
@@ -31,7 +32,9 @@
*/
enum ds_type {
ds_1307,
+ ds_1337,
ds_1338,
+ ds_1341,
last_ds_type /* always last */
};
@@ -62,6 +65,28 @@ enum ds_type {
# define DS1307_BIT_SQWE 0x10
# define DS1307_BIT_RS1 0x02
# define DS1307_BIT_RS0 0x01
+#define DS1337_REG_CONTROL 0x0e
+# define DS1337_BIT_nEOSC 0x80
+# define DS1339_BIT_BBSQI 0x20
+# define DS3231_BIT_BBSQW 0x40 /* same as BBSQI */
+# define DS1337_BIT_RS2 0x10
+# define DS1337_BIT_RS1 0x08
+# define DS1337_BIT_INTCN 0x04
+# define DS1337_BIT_A2IE 0x02
+# define DS1337_BIT_A1IE 0x01
+#define DS1340_REG_CONTROL 0x07
+# define DS1340_BIT_OUT 0x80
+# define DS1340_BIT_FT 0x40
+# define DS1340_BIT_CALIB_SIGN 0x20
+# define DS1340_M_CALIBRATION 0x1f
+#define DS1340_REG_FLAG 0x09
+# define DS1340_BIT_OSF 0x80
+#define DS1337_REG_STATUS 0x0f
+# define DS1337_BIT_OSF 0x80
+# define DS1341_BIT_ECLK 0x04
+# define DS1337_BIT_A2I 0x02
+# define DS1337_BIT_A1I 0x01
+
struct ds1307 {
struct rtc_device rtc;
@@ -78,7 +103,9 @@ struct ds1307 {
static struct platform_device_id ds1307_id[] = {
{ "ds1307", ds_1307 },
+ { "ds1337", ds_1337 },
{ "ds1338", ds_1338 },
+ { "ds1341", ds_1341 },
{ "pt7c4338", ds_1307 },
{ }
};
@@ -224,6 +251,16 @@ static int ds1307_set_time(struct rtc_device *rtcdev, struct rtc_time *t)
tmp = t->tm_year - 100;
buf[DS1307_REG_YEAR] = bin2bcd(tmp);
+ switch (ds1307->type) {
+ case ds_1337:
+ case ds_1341:
+ buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
+ break;
+ default:
+ break;
+ }
+
+
dev_dbg(dev, "%s: %7ph\n", "write", buf);
result = ds1307->write_block_data(ds1307->client,
@@ -263,6 +300,61 @@ static int ds1307_probe(struct device_d *dev)
ds1307->read_block_data = ds1307_read_block_data;
ds1307->write_block_data = ds1307_write_block_data;
+
+ switch (ds1307->type) {
+ case ds_1337:
+ case ds_1341:
+ /* get registers that the "rtc" read below won't read... */
+ tmp = ds1307->read_block_data(ds1307->client,
+ DS1337_REG_CONTROL, 2, buf);
+
+ if (tmp != 2) {
+ dev_dbg(&client->dev, "read error %d\n", tmp);
+ err = -EIO;
+ goto exit;
+ }
+
+ /* oscillator off? turn it on, so clock can tick. */
+ if (ds1307->regs[0] & DS1337_BIT_nEOSC)
+ ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
+
+
+ /*
+ Make sure no alarm interrupts or square wave signals
+ are produced by the chip while we are in
+ bootloader. We do this by configuring the RTC to
+ generate alarm interrupts (thus disabling square
+ wave generation), but disabling each individual
+ alarm interrupt source
+ */
+ ds1307->regs[0] |= DS1337_BIT_INTCN;
+ ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+
+ i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
+ ds1307->regs[0]);
+
+ /*
+ For the above to be true, DS1341 also has to have
+ ECLK bit set to 0
+ */
+ if (ds1307->type == ds_1341) {
+ ds1307->regs[1] &= DS1341_BIT_ECLK;
+ i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
+ ds1307->regs[1]);
+ }
+
+
+ /* oscillator fault? clear flag, and warn */
+ if (ds1307->regs[1] & DS1337_BIT_OSF) {
+ i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
+ ds1307->regs[1] & ~DS1337_BIT_OSF);
+ dev_warn(&client->dev, "SET TIME!\n");
+ }
+
+ default:
+ break;
+ }
+
read_rtc:
/* read RTC registers */
tmp = ds1307->read_block_data(client, ds1307->offset, 8, buf);
@@ -331,6 +423,8 @@ read_rtc:
err = rtc_register(&ds1307->rtc);
exit:
+ if (err)
+ free(ds1307);
return err;
}
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 1b23458a57..83d80455da 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -90,6 +90,8 @@ int rtc_valid_tm(struct rtc_time *tm)
{
if (tm->tm_year < 70
|| ((unsigned)tm->tm_mon) >= 12
+ || tm->tm_wday < 0
+ || tm->tm_wday > 6
|| tm->tm_mday < 1
|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
|| ((unsigned)tm->tm_hour) >= 24
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))
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index eabd246d53..7ff67e525e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -82,11 +82,11 @@ config DRIVER_VIDEO_PXA
Add support for the frame buffer device found on the PXA270
CPU.
-config DRIVER_VIDEO_BCM2835
- bool "BCM2835 framebuffer driver"
- depends on ARCH_BCM2835
+config DRIVER_VIDEO_BCM283X
+ bool "BCM283X framebuffer driver"
+ depends on ARCH_BCM283X
help
- Add support for the BCM2835/VideoCore frame buffer device.
+ Add support for the BCM283X/VideoCore frame buffer device.
source drivers/video/imx-ipu-v3/Kconfig
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 57e4864a6d..a64fc5f24d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -17,6 +17,6 @@ obj-$(CONFIG_DRIVER_VIDEO_S3C24XX) += s3c24xx.o
obj-$(CONFIG_DRIVER_VIDEO_PXA) += pxa.o
obj-$(CONFIG_DRIVER_VIDEO_SDL) += sdl.o
obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
-obj-$(CONFIG_DRIVER_VIDEO_BCM2835) += bcm2835.o
+obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/