summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-07-09 08:21:06 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2018-07-09 08:21:06 +0200
commit47d229d5c0fc626707101f0ad6c653ee68a65616 (patch)
treef893f4b10972f0886d94bea547ed20fc2523246f /drivers
parent0d0e894257392e6d7fbcc03991ee16b334d2f1ed (diff)
parent8470a9eeca22e3d169375241424306be9c5e5838 (diff)
downloadbarebox-47d229d5c0fc626707101f0ad6c653ee68a65616.tar.gz
barebox-47d229d5c0fc626707101f0ad6c653ee68a65616.tar.xz
Merge branch 'for-next/imx'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/imx/clk-gate2.c17
-rw-r--r--drivers/clk/imx/clk-imx6.c1
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c6
-rw-r--r--drivers/mtd/nand/nand_mxs.c5
-rw-r--r--drivers/nvmem/Kconfig7
-rw-r--r--drivers/nvmem/Makefile5
-rw-r--r--drivers/nvmem/core.c23
-rw-r--r--drivers/nvmem/rave-sp-eeprom.c370
-rw-r--r--drivers/usb/core/common.c12
-rw-r--r--drivers/usb/core/of.c24
-rw-r--r--drivers/usb/imx/chipidea-imx.c13
-rw-r--r--drivers/video/Kconfig7
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/rave-sp-backlight.c72
-rw-r--r--drivers/watchdog/rave-sp-wdt.c82
15 files changed, 582 insertions, 64 deletions
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index e7dcd87a7e..f2e704cdb2 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -129,20 +129,3 @@ struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg,
return g;
}
-
-struct clk *clk_gate2_inverted(const char *name, const char *parent,
- void __iomem *reg, u8 shift)
-{
- struct clk *clk;
- struct clk_gate2 *g;
-
- clk = clk_gate2(name, parent, reg, shift, 0x3, 0);
- if (IS_ERR(clk))
- return clk;
-
- g = to_clk_gate2(clk);
-
- g->flags = CLK_GATE_INVERTED;
-
- return clk;
-}
diff --git a/drivers/clk/imx/clk-imx6.c b/drivers/clk/imx/clk-imx6.c
index 8c3bb46a48..35b995dae2 100644
--- a/drivers/clk/imx/clk-imx6.c
+++ b/drivers/clk/imx/clk-imx6.c
@@ -527,7 +527,6 @@ static int imx6_ccm_probe(struct device_d *dev)
clk_enable(clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF]);
clk_enable(clks[IMX6QDL_CLK_PLL6_ENET]);
clk_enable(clks[IMX6QDL_CLK_SATA_REF_100M]);
- clk_enable(clks[IMX6QDL_CLK_ENFC_PODF]);
clk_set_parent(clks[IMX6QDL_CLK_LVDS1_SEL], clks[IMX6QDL_CLK_SATA_REF_100M]);
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 4b8eaec057..7980a91e19 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -246,9 +246,6 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
command = priv->command;
- dev_dbg(&priv->spi->dev, "READ: (%x) %x %x %x\n",
- command[0], command[1], command[2], command[3]);
-
spi_message_init(&msg);
memset(&x[0], 0, sizeof(struct spi_transfer) * 2);
@@ -271,6 +268,9 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
command[3] = (u8)(addr >> 0);
/* plus 4 "don't care" bytes */
+ dev_dbg(&priv->spi->dev, "READ: (%x) %x %x %x\n",
+ command[0], command[1], command[2], command[3]);
+
status = spi_sync(priv->spi, &msg);
if (status >= 0) {
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index 337748af48..0e0f5e68b2 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -2051,7 +2051,9 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
nand->select_chip(mtd, -1);
/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
+ clk_disable(info->clk);
clk_set_rate(info->clk, (mode == 5) ? 100000000 : 80000000);
+ clk_enable(info->clk);
dev_dbg(info->dev, "using asynchronous EDO mode %d\n", mode);
@@ -2147,6 +2149,8 @@ static int mxs_nand_probe(struct device_d *dev)
if (IS_ERR(nand_info->clk))
return PTR_ERR(nand_info->clk);
+ clk_enable(nand_info->clk);
+
if (mxs_nand_is_imx6(nand_info)) {
clk_disable(nand_info->clk);
clk_set_rate(nand_info->clk, 22000000);
@@ -2154,7 +2158,6 @@ static int mxs_nand_probe(struct device_d *dev)
nand_info->dma_channel_base = 0;
} else {
nand_info->dma_channel_base = MXS_DMA_CHANNEL_AHB_APBH_GPMI0;
- clk_enable(nand_info->clk);
}
err = mxs_nand_alloc_buffers(nand_info);
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index a3797b4aac..38b6f42419 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -36,4 +36,11 @@ config IMX_OCOTP_WRITE
the value of the address by 4.
mw -l -d /dev/imx-ocotp 0x8C 0x00001234
mw -l -d /dev/imx-ocotp 0x88 0x56789ABC
+
+config RAVE_SP_EEPROM
+ tristate "Rave SP EEPROM Support"
+ depends on RAVE_SP_CORE
+ help
+ Say y here to enable Rave SP EEPROM support.
+
endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 998a9c4b9a..716e5dbe87 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -10,4 +10,7 @@ obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o
nvmem_snvs_lpgpr-y := snvs_lpgpr.o
obj-$(CONFIG_IMX_OCOTP) += nvmem_ocotp.o
-nvmem_ocotp-y := ocotp.o \ No newline at end of file
+nvmem_ocotp-y := ocotp.o
+
+obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o
+nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o \ No newline at end of file
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 53b934bb33..c0f61f453a 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -750,3 +750,26 @@ int nvmem_device_write(struct nvmem_device *nvmem,
return bytes;
}
EXPORT_SYMBOL_GPL(nvmem_device_write);
+
+void *nvmem_cell_get_and_read(struct device_node *np, const char *cell_name,
+ size_t bytes)
+{
+ struct nvmem_cell *cell;
+ void *value;
+ size_t len;
+
+ cell = of_nvmem_cell_get(np, cell_name);
+ if (IS_ERR(cell))
+ return cell;
+
+ value = nvmem_cell_read(cell, &len);
+ if (!IS_ERR(value) && len != bytes) {
+ kfree(value);
+ value = ERR_PTR(-EINVAL);
+ }
+
+ nvmem_cell_put(cell);
+
+ return value;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_get_and_read);
diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c
new file mode 100644
index 0000000000..6c6ed17f18
--- /dev/null
+++ b/drivers/nvmem/rave-sp-eeprom.c
@@ -0,0 +1,370 @@
+/*
+ * EEPROM driver for RAVE SP
+ *
+ * Copyright (C) 2017 Zodiac Inflight Innovations
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <of_device.h>
+#include <malloc.h>
+#include <linux/sizes.h>
+#include <linux/mfd/rave-sp.h>
+#include <linux/nvmem-provider.h>
+
+/**
+ * enum rave_sp_eeprom_access_type - Supported types of EEPROM access
+ *
+ * @RAVE_SP_EEPROM_WRITE: EEPROM write
+ * @RAVE_SP_EEPROM_READ: EEPROM read
+ *
+ * Note that values of both constant are chose so that they'd match
+ * similar values from RAVE SP ICD.
+ */
+enum rave_sp_eeprom_access_type {
+ RAVE_SP_EEPROM_WRITE = 0,
+ RAVE_SP_EEPROM_READ = 1,
+};
+
+/**
+ * enum rave_sp_eeprom_header_size - EEPROM command header sizes
+ *
+ * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K)
+ * @RAVE_SP_EEPROM_HEADER_BIG: EEPROM header size for "big" devices (> 8K, < 2M)
+ *
+ * Note that values of both constant are chose so that they'd match
+ * similar values from RAVE SP ICD.
+ */
+enum rave_sp_eeprom_header_size {
+ RAVE_SP_EEPROM_HEADER_SMALL = 4U,
+ RAVE_SP_EEPROM_HEADER_BIG = 5U,
+};
+#define RAVE_SP_EEPROM_HEADER_MAX RAVE_SP_EEPROM_HEADER_BIG
+
+#define RAVE_SP_EEPROM_PAGE_SIZE 32U
+
+/**
+ * struct rave_sp_eeprom_page - RAVE SP EEPROM page
+ *
+ * @type: Access type (see enum rave_sp_eeprom_access_type)
+ * @success: Success flag (Success = 1, Failure = 0)
+ * @data: Read data
+ *
+ * Note that the layout of this structure is made to follow the layout
+ * of RSP_*_EEPROM from device's ICD (only the data portion of it due
+ * to how rave_sp_exec() returns data)
+ */
+struct rave_sp_eeprom_page {
+ u8 type;
+ u8 success;
+ u8 data[RAVE_SP_EEPROM_PAGE_SIZE];
+} __packed;
+
+/**
+ * struct rave_sp_eeprom - RAVE SP EEPROM device
+ *
+ * @sp: Pointer to parent RAVE SP device
+ * @mutex: Lock protecting access to EEPROM
+ * @address: EEPROM device address (first byte of the command to access it)
+ * @header_size: Size of EEPROM command header for this device
+ */
+struct rave_sp_eeprom {
+ struct rave_sp *sp;
+ u8 address;
+ unsigned int header_size;
+};
+
+/**
+ * rave_sp_eeprom_io - Low-level part of EEPROM page access
+ *
+ * @eeprom: EEPROM device to write to
+ * @type: EEPROM access type (read or write)
+ * @idx: number of the EEPROM page
+ * @page: Data to write or buffer to store result (via page->data)
+ *
+ * This function does all of the low-lever work required to perform a
+ * EEPROM access. This includes formatting corredct command payload,
+ * sending it and checking received results.
+ *
+ * Returns zero in case of success or negative error code in
+ * case of failure.
+ */
+static int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom,
+ enum rave_sp_eeprom_access_type type,
+ u16 idx,
+ struct rave_sp_eeprom_page *page)
+{
+ const bool is_write = type == RAVE_SP_EEPROM_WRITE;
+ const unsigned int data_size = is_write ? sizeof(page->data) : 0;
+ const unsigned int cmd_size = eeprom->header_size + data_size;
+ const unsigned int rsp_size =
+ is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page);
+ unsigned int offset = 0;
+ u8 cmd[RAVE_SP_EEPROM_HEADER_MAX + sizeof(page->data)];
+ int ret;
+
+ if (WARN_ON(cmd_size > sizeof(cmd)))
+ return -EINVAL;
+
+ cmd[offset++] = eeprom->address;
+ cmd[offset++] = 0;
+ cmd[offset++] = type;
+ cmd[offset++] = idx;
+
+ if (offset < eeprom->header_size)
+ cmd[offset++] = idx >> 8;
+ /*
+ * Copy our data to write to command buffer first. In case of
+ * a read data_size should be zero and memcpy would become a
+ * no-op
+ */
+ memcpy(&cmd[offset], page->data, data_size);
+
+ ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size);
+ if (ret)
+ return ret;
+
+ if (page->type != type)
+ return -EPROTO;
+
+ if (!page->success)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * rave_sp_eeprom_page_access - Access single EEPROM page
+ *
+ * @eeprom: EEPROM device to access
+ * @type: Access type to perform (read or write)
+ * @offset: Offset within EEPROM to access
+ * @data: Data buffer
+ * @data_len: Size of the data buffer
+ *
+ * This function performs a generic access to a single page or a
+ * portion thereof. Requested access MUST NOT cross the EEPROM page
+ * boundary.
+ *
+ * Returns zero in case of success or negative error code in
+ * case of failure.
+ */
+static int
+rave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom,
+ enum rave_sp_eeprom_access_type type,
+ unsigned int offset, u8 *data,
+ size_t data_len)
+{
+ const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE;
+ const unsigned int page_nr = offset / RAVE_SP_EEPROM_PAGE_SIZE;
+ struct rave_sp_eeprom_page page;
+ int ret;
+
+ /*
+ * This function will not work if data access we've been asked
+ * to do is crossing EEPROM page boundary. Normally this
+ * should never happen and getting here would indicate a bug
+ * in the code.
+ */
+ if (WARN_ON(data_len > sizeof(page.data) - page_offset))
+ return -EINVAL;
+
+ if (type == RAVE_SP_EEPROM_WRITE) {
+ /*
+ * If doing a partial write we need to do a read first
+ * to fill the rest of the page with correct data.
+ */
+ if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) {
+ ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ,
+ page_nr, &page);
+ if (ret)
+ return ret;
+ }
+
+ memcpy(&page.data[page_offset], data, data_len);
+ }
+
+ ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page);
+ if (ret)
+ return ret;
+
+ /*
+ * Since we receive the result of the read via 'page.data'
+ * buffer we need to copy that to 'data'
+ */
+ if (type == RAVE_SP_EEPROM_READ)
+ memcpy(data, &page.data[page_offset], data_len);
+
+ return 0;
+}
+
+/**
+ * rave_sp_eeprom_access - Access EEPROM data
+ *
+ * @eeprom: EEPROM device to access
+ * @type: Access type to perform (read or write)
+ * @offset: Offset within EEPROM to access
+ * @data: Data buffer
+ * @data_len: Size of the data buffer
+ *
+ * This function performs a generic access (either read or write) at
+ * arbitrary offset (not necessary page aligned) of arbitrary length
+ * (is not constrained by EEPROM page size).
+ *
+ * Returns zero in case of success or negative error code in case of
+ * failure.
+ */
+static int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom,
+ enum rave_sp_eeprom_access_type type,
+ unsigned int offset, u8 *data,
+ unsigned int data_len)
+{
+ unsigned int residue;
+ unsigned int chunk;
+ unsigned int head;
+ int ret;
+
+ head = offset % RAVE_SP_EEPROM_PAGE_SIZE;
+ residue = data_len;
+
+ do {
+ /*
+ * First iteration, if we are doing an access that is
+ * not 32-byte aligned, we need to access only data up
+ * to a page boundary to avoid corssing it in
+ * rave_sp_eeprom_page_access()
+ */
+ if (head) {
+ chunk = RAVE_SP_EEPROM_PAGE_SIZE - head;
+ /*
+ * This can only happen once per
+ * rave_sp_eeprom_access() call, so we set
+ * head to zero to process all the other
+ * iterations normally.
+ */
+ head = 0;
+ } else {
+ chunk = RAVE_SP_EEPROM_PAGE_SIZE;
+ }
+
+ /*
+ * We should never read more that 'residue' bytes
+ */
+ chunk = min(chunk, residue);
+ ret = rave_sp_eeprom_page_access(eeprom, type, offset,
+ data, chunk);
+ if (ret)
+ return ret;
+
+ residue -= chunk;
+ offset += chunk;
+ data += chunk;
+ } while (residue);
+
+ return 0;
+}
+
+static int rave_sp_eeprom_read(struct device_d *dev, const int offset,
+ void *val, int bytes)
+{
+ return rave_sp_eeprom_access(dev->parent->priv,
+ RAVE_SP_EEPROM_READ,
+ offset, val, bytes);
+}
+
+static int rave_sp_eeprom_write(struct device_d *dev, const int offset,
+ const void *val, int bytes)
+{
+ return rave_sp_eeprom_access(dev->parent->priv,
+ RAVE_SP_EEPROM_WRITE,
+ offset, (void *)val, bytes);
+}
+
+static const struct nvmem_bus rave_sp_eeprom_nvmem_bus = {
+ .write = rave_sp_eeprom_write,
+ .read = rave_sp_eeprom_read,
+};
+
+static int rave_sp_eeprom_probe(struct device_d *dev)
+{
+ struct rave_sp *sp = dev->parent->priv;
+ struct nvmem_config config = { 0 };
+ struct rave_sp_eeprom *eeprom;
+ struct nvmem_device *nvmem;
+ u32 reg[2], size;
+
+ if (of_property_read_u32_array(dev->device_node,
+ "reg", reg, ARRAY_SIZE(reg))) {
+ dev_err(dev, "Failed to parse \"reg\" property\n");
+ return -EINVAL;
+ }
+
+ size = reg[1];
+ /*
+ * Per ICD, we have no more than 2 bytes to specify EEPROM
+ * page.
+ */
+ if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) {
+ dev_err(dev, "Specified size is too big\n");
+ return -EINVAL;
+ }
+
+ eeprom = xzalloc(sizeof(*eeprom));
+ eeprom->address = reg[0];
+ eeprom->sp = sp;
+
+ dev->priv = eeprom;
+
+ if (size > SZ_8K)
+ eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG;
+ else
+ eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL;
+
+ config.name = dev_name(dev);
+ /*
+ * If a name is specified via DT, override the above with it.
+ */
+ of_property_read_string(dev->device_node, "zii,eeprom-name",
+ &config.name);
+ config.dev = dev;
+ config.word_size = 1;
+ config.stride = 1;
+ config.size = reg[1];
+ config.bus = &rave_sp_eeprom_nvmem_bus;
+
+ nvmem = nvmem_register(&config);
+ if (IS_ERR(nvmem)) {
+ free(eeprom);
+ return PTR_ERR(nvmem);
+ }
+
+ return 0;
+}
+
+static __maybe_unused const struct of_device_id rave_sp_eeprom_of_match[] = {
+ { .compatible = "zii,rave-sp-eeprom" },
+ {}
+};
+
+static struct driver_d rave_sp_eeprom_driver = {
+ .name = "rave-sp-eeprom",
+ .probe = rave_sp_eeprom_probe,
+ .of_compatible = DRV_OF_COMPAT(rave_sp_eeprom_of_match),
+};
+console_platform_driver(rave_sp_eeprom_driver);
diff --git a/drivers/usb/core/common.c b/drivers/usb/core/common.c
index 690d5a39ea..bcbe3a155d 100644
--- a/drivers/usb/core/common.c
+++ b/drivers/usb/core/common.c
@@ -17,3 +17,15 @@ const char *usb_speed_string(enum usb_device_speed speed)
return speed_names[speed];
}
EXPORT_SYMBOL_GPL(usb_speed_string);
+
+enum usb_device_speed usb_speed_by_string(const char *string)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(speed_names); i++)
+ if (!strcmp(string, speed_names[i]))
+ return i;
+
+ return USB_SPEED_UNKNOWN;
+}
+EXPORT_SYMBOL_GPL(usb_speed_by_string);
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
index fd20368424..979088ef4e 100644
--- a/drivers/usb/core/of.c
+++ b/drivers/usb/core/of.c
@@ -90,3 +90,27 @@ enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np,
return USBPHY_INTERFACE_MODE_UNKNOWN;
}
EXPORT_SYMBOL_GPL(of_usb_get_phy_mode);
+
+/**
+ * of_usb_get_maximum_speed - Get maximum speed for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * The function gets maximum speed string from property 'maximum-speed',
+ * and returns the correspondig enum usb_device_speed
+ */
+enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np,
+ const char *propname)
+{
+ const char *maximum_speed;
+ int err;
+
+ if (!propname)
+ propname = "maximum-speed";
+
+ err = of_property_read_string(np, propname, &maximum_speed);
+ if (err < 0)
+ return USB_SPEED_UNKNOWN;
+
+ return usb_speed_by_string(maximum_speed);
+}
+EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index 505f5eb35d..3e3e6a365f 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -51,6 +51,7 @@ struct imx_chipidea {
static int imx_chipidea_port_init(void *drvdata)
{
struct imx_chipidea *ci = drvdata;
+ uint32_t portsc;
int ret;
if ((ci->flags & MXC_EHCI_PORTSC_MASK) == MXC_EHCI_MODE_ULPI) {
@@ -74,6 +75,14 @@ static int imx_chipidea_port_init(void *drvdata)
if (ret)
dev_err(ci->dev, "misc init failed: %s\n", strerror(-ret));
+ /* PFSC bit is reset by ehci_reset(), thus have to set it not in
+ * probe but here, after ehci_reset() is already called */
+ if (ci->flags & MXC_EHCI_PFSC) {
+ portsc = readl(ci->base + 0x184);
+ portsc |= MXC_EHCI_PFSC;
+ writel(portsc, ci->base + 0x184);
+ }
+
return ret;
}
@@ -159,6 +168,10 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
"over-current-active-high", NULL))
ci->flags |= MXC_EHCI_OC_PIN_ACTIVE_LOW;
+ if (of_usb_get_maximum_speed(ci->dev->device_node, NULL) ==
+ USB_SPEED_FULL)
+ ci->flags |= MXC_EHCI_PFSC;
+
return 0;
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1dcae48f80..79de32cf8e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -124,6 +124,13 @@ config DRIVER_VIDEO_BACKLIGHT_PWM
help
Enable this to get support for backlight devices driven by a PWM.
+config BACKLIGHT_RAVE_SP
+ tristate "RAVE SP Backlight driver"
+ depends on RAVE_SP_CORE
+ depends on DRIVER_VIDEO_BACKLIGHT
+ help
+ Support for backlight control on RAVE SP device.
+
comment "Video encoder chips"
config DRIVER_VIDEO_MTL017
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 081e4463d8..01fabe8809 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -23,3 +23,5 @@ obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
obj-$(CONFIG_DRIVER_VIDEO_EFI_GOP) += efi_gop.o
obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
+obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
+
diff --git a/drivers/video/rave-sp-backlight.c b/drivers/video/rave-sp-backlight.c
new file mode 100644
index 0000000000..88ec86e730
--- /dev/null
+++ b/drivers/video/rave-sp-backlight.c
@@ -0,0 +1,72 @@
+/*
+ * LCD Backlight driver for RAVE SP
+ *
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <init.h>
+#include <video/backlight.h>
+#include <linux/mfd/rave-sp.h>
+
+#define RAVE_SP_BACKLIGHT_LCD_EN BIT(7)
+
+static int rave_sp_backlight_set(struct backlight_device *bd, int brightness)
+{
+ struct rave_sp *sp = bd->dev.priv;
+ u8 cmd[] = {
+ [0] = RAVE_SP_CMD_SET_BACKLIGHT,
+ [1] = 0,
+ [2] = brightness ? RAVE_SP_BACKLIGHT_LCD_EN | brightness : 0,
+ [3] = 0,
+ [4] = 0,
+ };
+
+ return rave_sp_exec(sp, cmd, sizeof(cmd), NULL, 0);
+}
+
+static int rave_sp_backlight_probe(struct device_d *dev)
+{
+ struct backlight_device *bd;
+ int ret;
+
+ bd = xzalloc(sizeof(*bd));
+ bd->dev.priv = dev->parent->priv;
+ bd->brightness_default = 50;
+ bd->brightness_max = 100;
+ bd->brightness_set = rave_sp_backlight_set;
+
+ ret = backlight_register(bd);
+ if (ret) {
+ free(bd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rave_sp_backlight_of_match[] = {
+ { .compatible = "zii,rave-sp-backlight" },
+ {}
+};
+
+static struct driver_d rave_sp_backlight_driver = {
+ .name = "rave-sp-backlight",
+ .probe = rave_sp_backlight_probe,
+ .of_compatible = DRV_OF_COMPAT(rave_sp_backlight_of_match),
+};
+device_platform_driver(rave_sp_backlight_driver);
diff --git a/drivers/watchdog/rave-sp-wdt.c b/drivers/watchdog/rave-sp-wdt.c
index 1643167851..dc673ee35f 100644
--- a/drivers/watchdog/rave-sp-wdt.c
+++ b/drivers/watchdog/rave-sp-wdt.c
@@ -37,9 +37,6 @@ enum {
RAVE_SP_RESET_REASON_CP_REQUEST = 13,
RAVE_SP_RESET_DELAY_MS = 500,
-
- RAVE_SP_BOOT_SOURCE_GET = 0,
- RAVE_SP_BOOT_SOURCE_SET = 1,
};
/**
@@ -75,7 +72,7 @@ struct rave_sp_wdt {
struct restart_handler restart;
unsigned int timeout;
unsigned int boot_source;
- struct device_d dev;
+ struct nvmem_cell *boot_source_cell;
};
static struct rave_sp_wdt *to_rave_sp_wdt(struct watchdog *wdd)
@@ -90,26 +87,6 @@ static int rave_sp_wdt_exec(struct watchdog *wdd, void *data,
data, data_size, NULL, 0);
}
-
-static int rave_sp_wdt_access_boot_source(struct rave_sp_wdt *sp_wd, u8 set_get)
-{
- u8 cmd[] = {
- [0] = RAVE_SP_CMD_BOOT_SOURCE,
- [1] = 0,
- [2] = set_get,
- [3] = sp_wd->boot_source,
- };
- u8 response;
- int ret;
-
- ret = rave_sp_exec(sp_wd->sp, cmd, sizeof(cmd), &response,
- sizeof(response));
- if (ret)
- return ret;
-
- return response;
-}
-
static int __rave_sp_wdt_rdu_reset_reason(struct watchdog *wdd,
uint8_t response[],
size_t response_len)
@@ -278,9 +255,12 @@ static const struct of_device_id rave_sp_wdt_of_match[] = {
static int rave_sp_wdt_set_boot_source(struct param_d *param, void *priv)
{
+ struct rave_sp_wdt *sp_wd = priv;
+ u8 boot_source = sp_wd->boot_source;
int ret;
- ret = rave_sp_wdt_access_boot_source(priv, RAVE_SP_BOOT_SOURCE_SET);
+ ret = nvmem_cell_write(sp_wd->boot_source_cell, &boot_source,
+ sizeof(boot_source));
if (ret < 0)
return ret;
@@ -290,13 +270,38 @@ static int rave_sp_wdt_set_boot_source(struct param_d *param, void *priv)
static int rave_sp_wdt_get_boot_source(struct param_d *param, void *priv)
{
struct rave_sp_wdt *sp_wd = priv;
- int ret;
+ u8 *boot_source;
+ size_t len;
- ret = rave_sp_wdt_access_boot_source(sp_wd, RAVE_SP_BOOT_SOURCE_GET);
- if (ret < 0)
- return ret;
+ boot_source = nvmem_cell_read(sp_wd->boot_source_cell, &len);
+ if (IS_ERR(boot_source))
+ return PTR_ERR(boot_source);
+
+ sp_wd->boot_source = *boot_source;
+ kfree(boot_source);
+
+ return 0;
+}
+
+static int rave_sp_wdt_add_params(struct rave_sp_wdt *sp_wd)
+{
+ struct watchdog *wdd = &sp_wd->wdd;
+ struct device_node *np = wdd->hwdev->device_node;
+ struct param_d *p;
+
+ sp_wd->boot_source_cell = of_nvmem_cell_get(np, "boot-source");
+ if (IS_ERR(sp_wd->boot_source_cell)) {
+ dev_warn(wdd->hwdev, "No bootsource info availible\n");
+ return 0;
+ }
+
+ p = dev_add_param_int(&wdd->dev, "boot_source",
+ rave_sp_wdt_set_boot_source,
+ rave_sp_wdt_get_boot_source,
+ &sp_wd->boot_source, "%u", sp_wd);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
- sp_wd->boot_source = ret;
return 0;
}
@@ -307,7 +312,6 @@ static int rave_sp_wdt_probe(struct device_d *dev)
struct nvmem_cell *cell;
struct watchdog *wdd;
__le16 timeout = 60;
- struct param_d *p;
int ret;
sp_wd = xzalloc(sizeof(*sp_wd));
@@ -344,6 +348,12 @@ static int rave_sp_wdt_probe(struct device_d *dev)
return ret;
}
+ ret = rave_sp_wdt_add_params(sp_wd);
+ if (ret) {
+ dev_err(dev, "Failed to register device parameters");
+ return ret;
+ }
+
sp_wd->restart.name = "rave-sp-wdt";
sp_wd->restart.restart = rave_sp_wdt_restart_handler;
sp_wd->restart.priority = 200;
@@ -352,16 +362,6 @@ static int rave_sp_wdt_probe(struct device_d *dev)
if (ret)
dev_warn(dev, "Cannot register restart handler\n");
-
- p = dev_add_param_int(&wdd->dev, "boot_source",
- rave_sp_wdt_set_boot_source,
- rave_sp_wdt_get_boot_source,
- &sp_wd->boot_source, "%u", sp_wd);
- if (IS_ERR(p)) {
- unregister_device(&sp_wd->dev);
- return PTR_ERR(p);
- }
-
ret = sp_wd->variant->reset_reason(wdd);
if (ret < 0) {
dev_warn(dev, "Failed to query reset reason\n");