diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2018-07-09 08:21:06 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2018-07-09 08:21:06 +0200 |
commit | 47d229d5c0fc626707101f0ad6c653ee68a65616 (patch) | |
tree | f893f4b10972f0886d94bea547ed20fc2523246f /drivers | |
parent | 0d0e894257392e6d7fbcc03991ee16b334d2f1ed (diff) | |
parent | 8470a9eeca22e3d169375241424306be9c5e5838 (diff) | |
download | barebox-47d229d5c0fc626707101f0ad6c653ee68a65616.tar.gz barebox-47d229d5c0fc626707101f0ad6c653ee68a65616.tar.xz |
Merge branch 'for-next/imx'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/imx/clk-gate2.c | 17 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx6.c | 1 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_mxs.c | 5 | ||||
-rw-r--r-- | drivers/nvmem/Kconfig | 7 | ||||
-rw-r--r-- | drivers/nvmem/Makefile | 5 | ||||
-rw-r--r-- | drivers/nvmem/core.c | 23 | ||||
-rw-r--r-- | drivers/nvmem/rave-sp-eeprom.c | 370 | ||||
-rw-r--r-- | drivers/usb/core/common.c | 12 | ||||
-rw-r--r-- | drivers/usb/core/of.c | 24 | ||||
-rw-r--r-- | drivers/usb/imx/chipidea-imx.c | 13 | ||||
-rw-r--r-- | drivers/video/Kconfig | 7 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/rave-sp-backlight.c | 72 | ||||
-rw-r--r-- | drivers/watchdog/rave-sp-wdt.c | 82 |
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"); |