From b652da253c5d9188c4ad102dab8cd99934a94fec Mon Sep 17 00:00:00 2001 From: Jon Nettleton Date: Sat, 17 Feb 2018 08:03:26 +0100 Subject: [PATCH 0001/3047] Revert "dmaengine: imx-sdma - correct the dma transfer residue calculation" This reverts commit 3a654a85932fa7a909b11934df7657c1a2cb3609. This was backported in NXP's branch and applied later through the process. Revert it here so it doesn't conflict in the rebase. --- drivers/dma/imx-sdma.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index d1651a50c3491e..b9629b2bfc050b 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -298,7 +298,6 @@ struct sdma_engine; * @event_id1 for channels that use 2 events * @word_size peripheral access size * @buf_tail ID of the buffer that was processed - * @buf_ptail ID of the previous buffer that was processed * @num_bd max NUM_BD. number of descriptors currently handling */ struct sdma_channel { @@ -310,7 +309,6 @@ struct sdma_channel { unsigned int event_id1; enum dma_slave_buswidth word_size; unsigned int buf_tail; - unsigned int buf_ptail; unsigned int num_bd; unsigned int period_len; struct sdma_buffer_descriptor *bd; @@ -702,8 +700,6 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac) sdmac->chn_real_count = bd->mode.count; bd->mode.status |= BD_DONE; bd->mode.count = sdmac->period_len; - sdmac->buf_ptail = sdmac->buf_tail; - sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd; /* * The callback is called from the interrupt context in order @@ -714,6 +710,9 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac) dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL); + sdmac->buf_tail++; + sdmac->buf_tail %= sdmac->num_bd; + if (error) sdmac->status = old_status; } @@ -1187,8 +1186,6 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( sdmac->flags = 0; sdmac->buf_tail = 0; - sdmac->buf_ptail = 0; - sdmac->chn_real_count = 0; dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", sg_len, channel); @@ -1291,8 +1288,6 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( sdmac->status = DMA_IN_PROGRESS; sdmac->buf_tail = 0; - sdmac->buf_ptail = 0; - sdmac->chn_real_count = 0; sdmac->period_len = period_len; sdmac->flags |= IMX_DMA_SG_LOOP; @@ -1390,7 +1385,7 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan, u32 residue; if (sdmac->flags & IMX_DMA_SG_LOOP) - residue = (sdmac->num_bd - sdmac->buf_ptail) * + residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len - sdmac->chn_real_count; else residue = sdmac->chn_count - sdmac->chn_real_count; From 0930a75df513296cf72dd80f4341f89faa5e699f Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 22 Jul 2015 10:34:02 +0800 Subject: [PATCH 0002/3047] MLK-11265-1 ARM: dts: add imx7d soc dtsi support Add new SoC i.MX7D dtsi and pinfunc head file. Signed-off-by: Anson Huang --- arch/arm/boot/dts/imx7d.dtsi | 358 ++++++++++++++++++++++++ include/dt-bindings/clock/imx7d-clock.h | 4 +- 2 files changed, 361 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index f6dee41a05d95b..d4a450e2fee272 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -83,6 +83,260 @@ }; }; }; + + busfreq { + compatible = "fsl,imx_busfreq"; + fsl,max_ddr_freq = <533000000>; + clocks = <&clks IMX7D_OSC_24M_CLK>, <&clks IMX7D_MAIN_AXI_ROOT_SRC>, + <&clks IMX7D_AHB_CHANNEL_ROOT_SRC>, <&clks IMX7D_PLL_SYS_PFD0_392M_CLK>, + <&clks IMX7D_DRAM_ROOT_SRC>, <&clks IMX7D_DRAM_ALT_ROOT_SRC>, + <&clks IMX7D_PLL_DRAM_MAIN_CLK>, <&clks IMX7D_DRAM_ALT_ROOT_CLK>, + <&clks IMX7D_PLL_SYS_PFD2_270M_CLK>, <&clks IMX7D_PLL_SYS_PFD1_332M_CLK>, + <&clks IMX7D_AHB_CHANNEL_ROOT_CLK>, <&clks IMX7D_MAIN_AXI_ROOT_DIV>; + clock-names = "osc", "axi_sel", "ahb_sel", "pfd0_392m", "dram_root", "dram_alt_sel", + "pll_dram", "dram_alt_root", "pfd2_270m", "pfd1_332m", "ahb", "axi"; + interrupts = <0 112 0x04>, <0 113 0x04>; + interrupt-names = "irq_busfreq_0", "irq_busfreq_1"; + }; + + caam_sm: caam-sm@00100000 { + compatible = "fsl,imx7d-caam-sm", "fsl,imx6q-caam-sm"; + reg = <0x00100000 0x3fff>; + }; + + irq_sec_vio: caam_secvio { + compatible = "fsl,imx7d-caam-secvio", "fsl,imx6q-caam-secvio"; + interrupts = ; + }; + + pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts = ; + status = "disabled"; + }; + + ocrams_ddr: sram@00900000 { + compatible = "fsl,ddr-lpm-sram"; + reg = <0x00900000 0x1000>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + + ocram: sram@901000 { + compatible = "mmio-sram"; + reg = <0x00901000 0x1f000>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + + ocrams: sram@00180000 { + compatible = "fsl,lpm-sram"; + reg = <0x00180000 0x8000>; + clocks = <&clks IMX7D_OCRAM_S_CLK>; + status = "disabled"; + }; + + ocrams_mf: sram-mf@00900000 { + compatible = "fsl,mega-fast-sram"; + reg = <0x00900000 0x20000>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + + dma_apbh: dma-apbh@33000000 { + compatible = "fsl,imx7d-dma-apbh", "fsl,imx28-dma-apbh"; + reg = <0x33000000 0x2000>; + interrupts = , + , + , + ; + interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3"; + #dma-cells = <1>; + dma-channels = <4>; + clocks = <&clks IMX7D_NAND_USDHC_BUS_ROOT_CLK>, + <&clks IMX7D_NAND_ROOT_CLK>; + clock-names = "dma_apbh_bch", "dma_apbh_io"; + }; + + pcie: pcie@0x33800000 { + compatible = "fsl,imx7d-pcie", "snps,dw-pcie"; + reg = <0x33800000 0x4000>, <0x4ff00000 0x80000>; + reg-names = "dbi", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x4ff80000 0 0x00010000 /* downstream I/O 64KB */ + 0x82000000 0 0x40000000 0x40000000 0 0x0ff00000>; /* non-prefetchable memory */ + num-lanes = <1>; + interrupts = ; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX7D_PCIE_CTRL_ROOT_CLK>, + <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>, + <&clks IMX7D_PCIE_PHY_ROOT_CLK>; + clock-names = "pcie", "pcie_bus", "pcie_phy"; + pcie-phy-supply = <®_1p0d>; + status = "disabled"; + }; + }; +}; + +&aips1 { + kpp: kpp@30320000 { + compatible = "fsl,imx7d-kpp", "fsl,imx21-kpp"; + reg = <0x30320000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_CLK_DUMMY>; + status = "disabled"; + }; + + mqs: mqs { + compatible = "fsl,imx6sx-mqs"; + gpr = <&gpr>; + status = "disabled"; + }; + + ocotp-fuse@30350000 { + compatible = "fsl,imx7d-ocotp"; + reg = <0x30350000 0x10000>; + clocks = <&clks IMX7D_OCOTP_CLK>; + }; + + tempmon: tempmon { + compatible = "fsl,imx7d-tempmon"; + interrupts = ; + fsl,tempmon =<&anatop>; + fsl,tempmon-data = <&ocotp>; + clocks = <&clks IMX7D_PLL_SYS_MAIN_CLK>; + }; + + caam_snvs: caam-snvs@30370000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x30370000 0x10000>; + }; + + gpc: gpc@303a0000 { + compatible = "fsl,imx7d-gpc"; + reg = <0x303a0000 0x10000>; + interrupt-controller; + interrupts = ; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + fsl,mf-mix-wakeup-irq = <0x54010000 0xc00 0x0 0x1040640>; + }; +}; + +&anatop { + reg_1p2: regulator-vdd1p2@220 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vdd1p2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + anatop-reg-offset = <0x220>; + anatop-vol-bit-shift = <8>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <8>; + anatop-min-voltage = <1100000>; + anatop-max-voltage = <1300000>; + anatop-enable-bit = <31>; + }; +}; + +&aips2 { + flextimer1: flextimer@30640000 { + compatible = "fsl,imx7d-flextimer"; + reg = <0x30640000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + flextimer2: flextimer@30650000 { + compatible = "fsl,imx7d-flextimer"; + reg = <0x30650000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + system_counter_rd: system-counter-rd@306a0000 { + compatible = "fsl,imx7d-system-counter-rd"; + reg = <0x306a0000 0x10000>; + status = "disabled"; + }; + + system_counter_cmp: system-counter-cmp@306b0000 { + compatible = "fsl,imx7d-system-counter-cmp"; + reg = <0x306b0000 0x10000>; + status = "disabled"; + }; + + system_counter_ctrl: system-counter-ctrl@306c0000 { + compatible = "fsl,imx7d-system-counter-ctrl"; + reg = <0x306c0000 0x10000>; + interrupts = , + ; + status = "disabled"; + }; + + epdc: epdc@306f0000 { + compatible = "fsl,imx7d-epdc"; + interrupts = ; + reg = <0x306f0000 0x10000>; + clocks = <&clks IMX7D_CLK_DUMMY>, <&clks IMX7D_EPDC_PIXEL_ROOT_CLK>; + clock-names = "epdc_axi", "epdc_pix"; + epdc-ram = <&gpr 0x4 30>; + status = "disabled"; + }; + + epxp: epxp@30700000 { + compatible = "fsl,imx7d-pxp-dma"; + interrupts = , + ; + reg = <0x30700000 0x10000>; + clocks = <&clks IMX7D_CLK_DUMMY>; + clock-names = "pxp-axi"; + status = "disabled"; + }; + + csi1: csi@30710000 { + compatible = "fsl,imx7d-csi", "fsl,imx6s-csi"; + reg = <0x30710000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_CLK_DUMMY>, + <&clks IMX7D_CSI_MCLK_ROOT_CLK>, + <&clks IMX7D_CLK_DUMMY>; + clock-names = "disp-axi", "csi_mclk", "disp_dcic"; + status = "disabled"; + }; + + mipi_csi: mipi-csi@30750000 { + compatible = "fsl,imx7d-mipi-csi"; + reg = <0x30750000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_MIPI_CSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "mipi_clk", "phy_clk"; + mipi-phy-supply = <®_1p0d>; + csis-phy-reset = <&src 0x28 1>; + bus-width = <4>; + status = "disabled"; + }; + + mipi_dsi: mipi-dsi@30760000 { + compatible = "fsl,imx7d-mipi-dsi"; + reg = <0x30760000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_MIPI_DSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "mipi_cfg_clk", "mipi_pllref_clk"; + mipi-phy-supply = <®_1p0d>; + status = "disabled"; + }; + + ddrc: ddrc@307a0000 { + compatible = "fsl,imx7-ddrc"; + reg = <0x307a0000 0x10000>; }; }; @@ -127,6 +381,110 @@ fsl,num-rx-queues=<3>; status = "disabled"; }; + + crypto: caam@30900000 { + compatible = "fsl,imx7d-caam", "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x30900000 0x40000>; + ranges = <0 0x30900000 0x40000>; + interrupts = ; + clocks = <&clks IMX7D_CAAM_CLK>, + <&clks IMX7D_AHB_CHANNEL_ROOT_CLK>; + clock-names = "caam_ipg", "caam_aclk"; + sec_jr0: jr0@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupts = ; + }; + + sec_jr1: jr1@2000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupts = ; + }; + + sec_jr2: jr2@3000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupts = ; + }; + }; + + mu: mu@30aa0000 { + compatible = "fsl,imx7d-mu", "fsl,imx6sx-mu"; + reg = <0x30aa0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_MU_ROOT_CLK>; + clock-names = "mu"; + status = "okay"; + }; + + mcctest: mcctest{ + compatible = "fsl,imx6sx-mcc-test"; + status = "disabled"; + }; + + mcctty: mcctty{ + compatible = "fsl,imx6sx-mcc-tty"; + status = "disabled"; + }; + + rpmsg: rpmsg{ + compatible = "fsl,imx7d-rpmsg"; + status = "disabled"; + }; + + sema4: sema4@30ac0000 { + compatible = "fsl,imx7d-sema4"; + reg = <0x30ac0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_SEMA4_HS_ROOT_CLK>; + clock-names = "sema4"; + status = "okay"; + }; + + sim1: sim@30b90000 { + compatible = "fsl,imx7d-sim"; + reg = <0x30b90000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_SIM1_ROOT_CLK>; + clock-names = "sim"; + status = "disabled"; + }; + + sim2: sim@30ba0000 { + compatible = "fsl,imx7d-sim"; + reg = <0x30ba0000 0x10000>; + interrupts = ; + status = "disabled"; + }; + + qspi1: qspi@30bb0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx7d-qspi"; + reg = <0x30bb0000 0x10000>, <0x60000000 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = ; + clocks = <&clks IMX7D_QSPI_ROOT_CLK>, + <&clks IMX7D_QSPI_ROOT_CLK>; + clock-names = "qspi_en", "qspi"; + status = "disabled"; + }; + + weim: weim@30bc0000 { + compatible = "fsl,imx7d-weim", "fsl,imx6sx-weim", "fsl,imx6q-weim"; + reg = <0x30bc0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_EIM_ROOT_CLK>; + status = "disabled"; + }; + +}; + +&usbphynop3 { + vcc-supply = <®_1p2>; }; &ca_funnel_ports { diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h index 1183347c383fe1..f09e890f832dcd 100644 --- a/include/dt-bindings/clock/imx7d-clock.h +++ b/include/dt-bindings/clock/imx7d-clock.h @@ -449,5 +449,7 @@ #define IMX7D_ADC_ROOT_CLK 436 #define IMX7D_CLK_ARM 437 #define IMX7D_CKIL 438 -#define IMX7D_CLK_END 439 +#define IMX7D_OCOTP_CLK 439 +#define IMX7D_CAAM_CLK 440 +#define IMX7D_CLK_END 441 #endif /* __DT_BINDINGS_CLOCK_IMX7D_H */ From 3d0c82105721247ad837ed03121827878f438161 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 22 Jul 2015 10:35:01 +0800 Subject: [PATCH 0003/3047] MLK-11265-2 ARM: dts: add imx7d board dtb Add i.MX7D 12x12 LPDDR3 ARM2 board and SabreSD board dtb support. Signed-off-by: Anson Huang --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts | 174 ++++++++++++++++++ 2 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 7037201c5e3a7d..b254b26aa19849 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -431,7 +431,8 @@ dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-sbc-imx7.dtb \ imx7d-sdb.dtb \ imx7s-colibri-eval-v3.dtb \ - imx7s-warp.dtb + imx7s-warp.dtb \ + imx7d-12x12-lpddr3-arm2.dtb dtb-$(CONFIG_SOC_LS1021A) += \ ls1021a-qds.dtb \ ls1021a-twr.dtb diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts new file mode 100644 index 00000000000000..19cbc6a09f6913 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/dts-v1/; + +#include "imx7d.dtsi" + +/ { + model = "Freescale i.MX7 LPDDR3 12x12 ARM2 Board"; + compatible = "fsl,imx7d-12x12-lpddr3-arm2", "fsl,imx7d"; + + regulators { + compatible = "simple-bus"; + + reg_sd1_vmmc: sd1_vmmc{ + compatible = "regulator-fixed"; + regulator-name = "VCC_SD1"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_sd2_vmmc: sd2_vmmc{ + compatible = "regulator-fixed"; + regulator-name = "VCC_SD2"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; + + memory { + reg = <0x80000000 0x80000000>; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog_1>; + + imx7d-12x12-lpddr3-arm2 { + pinctrl_hog_1: hoggrp-1 { + fsl,pins = < + MX7D_PAD_I2C4_SCL__GPIO4_IO14 0x80000000 + MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31 0x80000000 + MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20 0x80000000 + MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21 0x80000000 + MX7D_PAD_ECSPI2_MISO__GPIO4_IO22 0x80000000 + MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x80000000 + MX7D_PAD_ECSPI1_MOSI__GPIO4_IO17 0x80000000 + MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0x17059 + MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x17059 + MX7D_PAD_SD1_WP__GPIO5_IO1 0x17059 + MX7D_PAD_SD2_CD_B__GPIO5_IO9 0x17059 + MX7D_PAD_SD2_WP__GPIO5_IO10 0x17059 + MX7D_PAD_SD2_RESET_B__GPIO5_IO11 0x17059 + MX7D_PAD_GPIO1_IO12__SD2_VSELECT 0x17059 + >; + }; + + pinctrl_uart1_1: uart1grp-1 { + fsl,pins = < + MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 + MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x79 + >; + }; + + pinctrl_usdhc1_1: usdhc1grp-1 { + fsl,pins = < + MX7D_PAD_SD1_CMD__SD1_CMD 0x17059 + MX7D_PAD_SD1_CLK__SD1_CLK 0x10059 + MX7D_PAD_SD1_DATA0__SD1_DATA0 0x17059 + MX7D_PAD_SD1_DATA1__SD1_DATA1 0x17059 + MX7D_PAD_SD1_DATA2__SD1_DATA2 0x17059 + MX7D_PAD_SD1_DATA3__SD1_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_1: usdhc2grp-1 { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x17059 + MX7D_PAD_SD2_CLK__SD2_CLK 0x10059 + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x17059 + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x17059 + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x17059 + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_1_100mhz: usdhc2grp-1_100mhz { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX7D_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x170b9 + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x170b9 + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x170b9 + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc2_1_200mhz: usdhc2grp-1_200mhz { + fsl,pins = < + MX7D_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX7D_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX7D_PAD_SD2_DATA0__SD2_DATA0 0x170f9 + MX7D_PAD_SD2_DATA1__SD2_DATA1 0x170f9 + MX7D_PAD_SD2_DATA2__SD2_DATA2 0x170f9 + MX7D_PAD_SD2_DATA3__SD2_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc3_1: usdhc3grp-1 { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x17059 + MX7D_PAD_SD3_CLK__SD3_CLK 0x10059 + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x17059 + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x17059 + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x17059 + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x17059 + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x17059 + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x17059 + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x17059 + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x17059 + >; + }; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1_1>; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1_1>; + cd-gpios = <&gpio5 0 0>; + wp-gpios = <&gpio5 1 0>; + no-1-8-v; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd1_vmmc>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2_1>; + pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>; + cd-gpios = <&gpio5 9 0>; + wp-gpios = <&gpio5 10 0>; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd2_vmmc>; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3_1>; + bus-width = <8>; + non-removable; + keep-power-in-suspend; + status = "okay"; +}; From 005c3c9ff24731fe9bf6b54b173e07519da0dfcc Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 27 Oct 2016 13:55:15 +0300 Subject: [PATCH 0004/3047] MLK-11265-6 ARM: imx: add imx7d msl support Add MSL support for new SoC i.MX7D. Signed-off-by: Anson Huang [Octavian: update upstream with minimal diff from mx_4.1.y to allow compile] Signed-off-by: Octavian Purdila --- arch/arm/mach-imx/hardware.h | 14 ++++++--- arch/arm/mach-imx/mx7.h | 48 +++++++++++++++++++++++++++++ drivers/clocksource/timer-imx-gpt.c | 1 + 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-imx/mx7.h diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h index 90e10cbd8fd11d..082e5895387271 100644 --- a/arch/arm/mach-imx/hardware.h +++ b/arch/arm/mach-imx/hardware.h @@ -94,18 +94,22 @@ * CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000 * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000 * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000 - */ + * mx7d: + * CCM 0x30380000+0x010000 -> 0xf5380000+0x010000 + * ANATOP 0x30360000+0x010000 -> 0xf5360000+0x010000 + * UART1 0x30860000+0x010000 -> 0xf5860000+0x010000 +*/ #define IMX_IO_P2V(x) ( \ - (((x) & 0x80000000) >> 7) | \ (0xf4000000 + \ - (((x) & 0x50000000) >> 6) + \ - (((x) & 0x0b000000) >> 4) + \ - (((x) & 0x000fffff)))) + (((x) & 0x50000000) >> 4) + \ + (((x) & 0x0a000000) >> 4) + \ + (((x) & 0x00ffffff)))) #define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x)) #include "mxc.h" +#include "mx7.h" #include "mx3x.h" #include "mx31.h" #include "mx35.h" diff --git a/arch/arm/mach-imx/mx7.h b/arch/arm/mach-imx/mx7.h new file mode 100644 index 00000000000000..97eff9cd7d8be5 --- /dev/null +++ b/arch/arm/mach-imx/mx7.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License version 2 as + * * published by the Free Software Foundation. + * */ + +#ifndef __ASM_ARCH_MX7_IOMAP_H__ +#define __ASM_ARCH_MX7_IOMAP_H__ + +#define MX7D_IO_P2V(x) IMX_IO_P2V(x) +#define MX7D_IO_ADDRESS(x) IOMEM(MX7D_IO_P2V(x)) + +#define MX7D_CCM_BASE_ADDR 0x30380000 +#define MX7D_CCM_SIZE 0x10000 +#define MX7D_IOMUXC_BASE_ADDR 0x30330000 +#define MX7D_IOMUXC_SIZE 0x10000 +#define MX7D_IOMUXC_GPR_BASE_ADDR 0x30340000 +#define MX7D_IOMUXC_GPR_SIZE 0x10000 +#define MX7D_ANATOP_BASE_ADDR 0x30360000 +#define MX7D_ANATOP_SIZE 0x10000 +#define MX7D_GPC_BASE_ADDR 0x303a0000 +#define MX7D_GPC_SIZE 0x10000 +#define MX7D_SRC_BASE_ADDR 0x30390000 +#define MX7D_SRC_SIZE 0x10000 +#define MX7D_DDRC_BASE_ADDR 0x307a0000 +#define MX7D_DDRC_SIZE 0x10000 +#define MX7D_DDRC_PHY_BASE_ADDR 0x30790000 +#define MX7D_DDRC_PHY_SIZE 0x10000 +#define MX7D_AIPS1_BASE_ADDR 0x30000000 +#define MX7D_AIPS1_SIZE 0x400000 +#define MX7D_AIPS2_BASE_ADDR 0x30400000 +#define MX7D_AIPS2_SIZE 0x400000 +#define MX7D_AIPS3_BASE_ADDR 0x30900000 +#define MX7D_AIPS3_SIZE 0x300000 + +#define TT_ATTRIB_NON_CACHEABLE_1M 0x802 +#define MX7_IRAM_TLB_SIZE 0x4000 +#define MX7_SUSPEND_OCRAM_SIZE 0x1000 +#define MX7_CPUIDLE_OCRAM_ADDR_OFFSET 0x1000 +#define MX7_CPUIDLE_OCRAM_SIZE 0x1000 +#define MX7_BUSFREQ_OCRAM_ADDR_OFFSET 0x2000 +#define MX7_BUSFREQ_OCRAM_SIZE 0x1000 + +#endif diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index f595460bfc589c..f3e2cbb9f15590 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -557,3 +557,4 @@ CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(mx7d_timer, "fsl,imx7d-gpt", imx6dl_timer_init_dt); From a4ab844e01f55fcc93f20451035670f5f263f956 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 20 Jul 2015 16:59:24 +0800 Subject: [PATCH 0005/3047] MLK-11265-9 ARM: imx: add ddrc driver support i.MX7D has a new IP block of DDR controller called DDRC, add driver for this module. Signed-off-by: Anson Huang --- arch/arm/mach-imx/Kconfig | 4 ++ arch/arm/mach-imx/Makefile | 1 + arch/arm/mach-imx/common.h | 2 +- arch/arm/mach-imx/ddrc.c | 86 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/mxc.h | 2 + 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/ddrc.c diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 9155b639c9aa9b..b33af656d0bb5f 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -54,6 +54,9 @@ config HAVE_IMX_GPC config HAVE_IMX_MMDC bool +config HAVE_IMX_DDRC + bool + config HAVE_IMX_SRC def_bool y if SMP select ARCH_HAS_RESET_CONTROLLER @@ -535,6 +538,7 @@ config SOC_IMX7D select HAVE_ARM_ARCH_TIMER select HAVE_IMX_ANATOP select HAVE_IMX_MMDC + select HAVE_IMX_DDRC select HAVE_IMX_SRC help This enables support for Freescale i.MX7 Dual processor. diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index cab128913e72a7..d7f5586d34aec3 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o +obj-$(CONFIG_HAVE_IMX_DDRC) += ddrc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) AFLAGS_headsmp.o :=-Wa,-march=armv7-a diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index c4436d9c52ff92..623c6454b4bb97 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -107,7 +107,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); int imx_mmdc_get_ddr_type(void); - +int imx_ddrc_get_ddr_type(void); void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); diff --git a/arch/arm/mach-imx/ddrc.c b/arch/arm/mach-imx/ddrc.c new file mode 100644 index 00000000000000..9c7f627d465e70 --- /dev/null +++ b/arch/arm/mach-imx/ddrc.c @@ -0,0 +1,86 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include + +#include "hardware.h" + +#define DDRC_MSTR 0x0 +#define BM_DDRC_MSTR_DDR3 0x1 +#define BM_DDRC_MSTR_LPDDR2 0x4 +#define BM_DDRC_MSTR_LPDDR3 0x8 + +static int ddr_type; + +static int imx_ddrc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + void __iomem *ddrc_base, *reg; + u32 val; + + ddrc_base = of_iomap(np, 0); + WARN_ON(!ddrc_base); + + reg = ddrc_base + DDRC_MSTR; + /* Get ddr type */ + val = readl_relaxed(reg); + val &= (BM_DDRC_MSTR_DDR3 | BM_DDRC_MSTR_LPDDR2 + | BM_DDRC_MSTR_LPDDR3); + + switch (val) { + case BM_DDRC_MSTR_DDR3: + pr_info("DDR type is DDR3!\n"); + ddr_type = IMX_DDR_TYPE_DDR3; + break; + case BM_DDRC_MSTR_LPDDR2: + pr_info("DDR type is LPDDR2!\n"); + ddr_type = IMX_DDR_TYPE_LPDDR2; + break; + case BM_DDRC_MSTR_LPDDR3: + pr_info("DDR type is LPDDR3!\n"); + ddr_type = IMX_DDR_TYPE_LPDDR3; + break; + default: + break; + } + + return 0; +} + +int imx_ddrc_get_ddr_type(void) +{ + return ddr_type; +} + +static struct of_device_id imx_ddrc_dt_ids[] = { + { .compatible = "fsl,imx7-ddrc", }, + { /* sentinel */ } +}; + +static struct platform_driver imx_ddrc_driver = { + .driver = { + .name = "imx-ddrc", + .owner = THIS_MODULE, + .of_match_table = imx_ddrc_dt_ids, + }, + .probe = imx_ddrc_probe, +}; + +static int __init imx_ddrc_init(void) +{ + return platform_driver_register(&imx_ddrc_driver); +} +postcore_initcall(imx_ddrc_init); diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 34f2ff62583c6e..9af12a684ba523 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -41,7 +41,9 @@ #define MXC_CPU_IMX6UL 0x64 #define MXC_CPU_IMX7D 0x72 +#define IMX_DDR_TYPE_DDR3 0 #define IMX_DDR_TYPE_LPDDR2 1 +#define IMX_DDR_TYPE_LPDDR3 2 #ifndef __ASSEMBLY__ extern unsigned int __mxc_cpu_type; From bdeed7ef16641aa9c73b338b39bb596805c90c31 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Thu, 27 Oct 2016 15:15:25 +0300 Subject: [PATCH 0006/3047] MLK-11265-8 ARM: imx: add pm support for imx7d Add i.MX7D suspend/resume support, including standby and mem mode support, mega/fast mix off and DDR retention support. Signed-off-by: Anson Huang --- arch/arm/mach-imx/Makefile | 5 +- arch/arm/mach-imx/anatop.c | 29 ++ arch/arm/mach-imx/common.h | 10 + arch/arm/mach-imx/gpcv2.c | 711 +++++++++++++++++++++++++++++++ arch/arm/mach-imx/mach-imx7d.c | 7 + arch/arm/mach-imx/pm-imx7.c | 626 +++++++++++++++++++++++++++ arch/arm/mach-imx/suspend-imx7.S | 567 ++++++++++++++++++++++++ 7 files changed, 1954 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/gpcv2.c create mode 100644 arch/arm/mach-imx/pm-imx7.c create mode 100644 arch/arm/mach-imx/suspend-imx7.S diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index d7f5586d34aec3..ffcd9ef50c2889 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o -obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o +obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o gpcv2.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_DDRC) += ddrc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o @@ -84,10 +84,13 @@ obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o ifeq ($(CONFIG_SUSPEND),y) AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a +AFLAGS_suspend-imx7.o :=-Wa,-march=armv7-a obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o +obj-$(CONFIG_SOC_IMX7D) += suspend-imx7.o obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o endif obj-$(CONFIG_SOC_IMX6) += pm-imx6.o +obj-$(CONFIG_SOC_IMX7D) += pm-imx7.o obj-$(CONFIG_SOC_IMX1) += mach-imx1.o obj-$(CONFIG_SOC_IMX50) += mach-imx50.o diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index 649a84c251ad6e..02c78acda93f94 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -21,6 +21,13 @@ #define REG_SET 0x4 #define REG_CLR 0x8 +#define ANADIG_ARM_PLL 0x60 +#define ANADIG_DDR_PLL 0x70 +#define ANADIG_SYS_PLL 0xb0 +#define ANADIG_ENET_PLL 0xe0 +#define ANADIG_AUDIO_PLL 0xf0 +#define ANADIG_VIDEO_PLL 0x130 + #define ANADIG_REG_2P5 0x130 #define ANADIG_REG_CORE 0x140 #define ANADIG_ANA_MISC0 0x150 @@ -74,6 +81,17 @@ static inline void imx_anatop_disconnect_high_snvs(bool enable) void imx_anatop_pre_suspend(void) { + if (cpu_is_imx7d()) { + /* PLL overwrite set */ + regmap_write(anatop, ANADIG_ARM_PLL + REG_SET, 1 << 20); + regmap_write(anatop, ANADIG_DDR_PLL + REG_SET, 1 << 19); + regmap_write(anatop, ANADIG_SYS_PLL + REG_SET, 1 << 17); + regmap_write(anatop, ANADIG_ENET_PLL + REG_SET, 1 << 13); + regmap_write(anatop, ANADIG_AUDIO_PLL + REG_SET, 1 << 24); + regmap_write(anatop, ANADIG_VIDEO_PLL + REG_SET, 1 << 24); + return; + } + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) imx_anatop_enable_2p5_pulldown(true); else @@ -87,6 +105,17 @@ void imx_anatop_pre_suspend(void) void imx_anatop_post_resume(void) { + if (cpu_is_imx7d()) { + /* PLL overwrite set */ + regmap_write(anatop, ANADIG_ARM_PLL + REG_CLR, 1 << 20); + regmap_write(anatop, ANADIG_DDR_PLL + REG_CLR, 1 << 19); + regmap_write(anatop, ANADIG_SYS_PLL + REG_CLR, 1 << 17); + regmap_write(anatop, ANADIG_ENET_PLL + REG_CLR, 1 << 13); + regmap_write(anatop, ANADIG_AUDIO_PLL + REG_CLR, 1 << 24); + regmap_write(anatop, ANADIG_VIDEO_PLL + REG_CLR, 1 << 24); + return; + } + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) imx_anatop_enable_2p5_pulldown(false); else diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 623c6454b4bb97..d971663a6114db 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -93,9 +93,15 @@ void imx_smp_prepare(void); static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} #endif +void imx7_pm_map_io(void); void imx_src_init(void); void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); +void imx_gpcv2_pre_suspend(bool arm_power_off); +void imx_gpcv2_post_resume(void); +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn); +unsigned int imx_gpcv2_is_mf_mix_off(void); +void __init imx_gpcv2_check_dt(void); void imx_gpc_mask_all(void); void imx_gpc_restore_all(void); void imx_gpc_hwirq_mask(unsigned int hwirq); @@ -113,14 +119,18 @@ int imx_cpu_kill(unsigned int cpu); #ifdef CONFIG_SUSPEND void v7_cpu_resume(void); +void ca7_cpu_resume(void); void imx53_suspend(void __iomem *ocram_vbase); extern const u32 imx53_suspend_sz; void imx6_suspend(void __iomem *ocram_vbase); +void imx7_suspend(void __iomem *ocram_vbase); #else static inline void v7_cpu_resume(void) {} +static inline void ca7_cpu_resume(void) {} static inline void imx53_suspend(void __iomem *ocram_vbase) {} static const u32 imx53_suspend_sz; static inline void imx6_suspend(void __iomem *ocram_vbase) {} +static inline void imx7_suspend(void __iomem *ocram_vbase) {} #endif void imx6_pm_ccm_init(const char *ccm_compat); diff --git a/arch/arm/mach-imx/gpcv2.c b/arch/arm/mach-imx/gpcv2.c new file mode 100644 index 00000000000000..e9e1a51d263310 --- /dev/null +++ b/arch/arm/mach-imx/gpcv2.c @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "hardware.h" + +#define IMR_NUM 4 +#define GPC_MAX_IRQS (IMR_NUM * 32) +#define GPC_LPCR_A7_BSC 0x0 +#define GPC_LPCR_A7_AD 0x4 +#define GPC_LPCR_M4 0x8 +#define GPC_SLPCR 0x14 +#define GPC_MLPCR 0x20 +#define GPC_PGC_ACK_SEL_A7 0x24 +#define GPC_MISC 0x2c +#define GPC_IMR1_CORE0 0x30 +#define GPC_IMR1_CORE1 0x40 +#define GPC_SLOT0_CFG 0xb0 +#define GPC_PGC_CPU_MAPPING 0xec +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0 +#define GPC_PU_PGC_SW_PUP_REQ 0xf8 +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc +#define GPC_PU_PGC_SW_PDN_REQ 0x104 +#define GPC_GTOR 0x124 +#define GPC_PGC_C0 0x800 +#define GPC_PGC_SCU_TIMING 0x890 +#define GPC_PGC_C1 0x840 +#define GPC_PGC_SCU 0x880 +#define GPC_PGC_FM 0xa00 +#define GPC_PGC_MIPI_PHY 0xc00 +#define GPC_PGC_PCIE_PHY 0xc40 +#define GPC_PGC_USB_OTG1_PHY 0xc80 +#define GPC_PGC_USB_OTG2_PHY 0xcc0 +#define GPC_PGC_USB_HSIC_PHY 0xd00 + +#define BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP 0x70000000 +#define BM_LPCR_A7_BSC_CPU_CLK_ON_LPM 0x4000 +#define BM_LPCR_A7_BSC_LPM1 0xc +#define BM_LPCR_A7_BSC_LPM0 0x3 +#define BP_LPCR_A7_BSC_LPM1 2 +#define BP_LPCR_A7_BSC_LPM0 0 +#define BM_LPCR_M4_MASK_DSM_TRIGGER 0x80000000 +#define BM_SLPCR_EN_DSM 0x80000000 +#define BM_SLPCR_RBC_EN 0x40000000 +#define BM_SLPCR_VSTBY 0x4 +#define BM_SLPCR_SBYOS 0x2 +#define BM_SLPCR_BYPASS_PMIC_READY 0x1 +#define BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE 0x10000 +#define BM_LPCR_A7_AD_L2PGE 0x10000 +#define BM_LPCR_A7_AD_EN_C1_PUP 0x800 +#define BM_LPCR_A7_AD_EN_C1_IRQ_PUP 0x400 +#define BM_LPCR_A7_AD_EN_C0_PUP 0x200 +#define BM_LPCR_A7_AD_EN_C0_IRQ_PUP 0x100 +#define BM_LPCR_A7_AD_EN_PLAT_PDN 0x10 +#define BM_LPCR_A7_AD_EN_C1_PDN 0x8 +#define BM_LPCR_A7_AD_EN_C1_WFI_PDN 0x4 +#define BM_LPCR_A7_AD_EN_C0_PDN 0x2 +#define BM_LPCR_A7_AD_EN_C0_WFI_PDN 0x1 + +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2 + +#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK 0x80000000 +#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK 0x8000 +#define BM_GPC_MLPCR_MEMLP_CTL_DIS 0x1 + +#define BP_LPCR_A7_BSC_IRQ_SRC 28 + +#define MAX_SLOT_NUMBER 10 +#define A7_LPM_WAIT 0x5 +#define A7_LPM_STOP 0xa + +enum imx_gpc_slot { + CORE0_A7, + CORE1_A7, + SCU_A7, + FAST_MEGA_MIX, + MIPI_PHY, + PCIE_PHY, + USB_OTG1_PHY, + USB_OTG2_PHY, + USB_HSIC_PHY, + CORE0_M4, +}; + +static void __iomem *gpc_base; +static u32 gpcv2_wake_irqs[IMR_NUM]; +static u32 gpcv2_saved_imrs[IMR_NUM]; +static u32 gpcv2_mf_irqs[IMR_NUM]; +static u32 gpcv2_mf_request_on[IMR_NUM]; +static DEFINE_SPINLOCK(gpcv2_lock); + +static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on) +{ + unsigned int idx = d->hwirq / 32; + unsigned long flags; + u32 mask; + + mask = 1 << d->hwirq % 32; + spin_lock_irqsave(&gpcv2_lock, flags); + gpcv2_wake_irqs[idx] = on ? gpcv2_wake_irqs[idx] | mask : + gpcv2_wake_irqs[idx] & ~mask; + spin_unlock_irqrestore(&gpcv2_lock, flags); + + return 0; +} + +void imx_gpcv2_mask_all(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + for (i = 0; i < IMR_NUM; i++) { + gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); + writel_relaxed(~0, reg_imr1 + i * 4); + } +} + +void imx_gpcv2_restore_all(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4); +} + +void imx_gpcv2_hwirq_unmask(unsigned int hwirq) +{ + void __iomem *reg; + u32 val; + + reg = gpc_base + GPC_IMR1_CORE0 + (hwirq / 32) * 4; + val = readl_relaxed(reg); + val &= ~(1 << hwirq % 32); + writel_relaxed(val, reg); +} + +void imx_gpcv2_hwirq_mask(unsigned int hwirq) +{ + void __iomem *reg; + u32 val; + + reg = gpc_base + GPC_IMR1_CORE0 + (hwirq / 32) * 4; + val = readl_relaxed(reg); + val |= 1 << (hwirq % 32); + writel_relaxed(val, reg); +} + +static void imx_gpcv2_irq_unmask(struct irq_data *d) +{ + imx_gpcv2_hwirq_unmask(d->hwirq); + irq_chip_unmask_parent(d); +} + +static void imx_gpcv2_irq_mask(struct irq_data *d) +{ + imx_gpcv2_hwirq_mask(d->hwirq); + irq_chip_mask_parent(d); +} + +void imx_gpcv2_set_slot_ack(u32 index, enum imx_gpc_slot m_core, + bool mode, bool ack) +{ + u32 val; + + if (index >= MAX_SLOT_NUMBER) + pr_err("Invalid slot index!\n"); + /* set slot */ + writel_relaxed((mode + 1) << (m_core * 2), gpc_base + + GPC_SLOT0_CFG + index * 4); + + if (ack) { + /* set ack */ + val = readl_relaxed(gpc_base + GPC_PGC_ACK_SEL_A7); + /* clear dummy ack */ + val &= ~(1 << (15 + (mode ? 16 : 0))); + val |= 1 << (m_core + (mode ? 16 : 0)); + writel_relaxed(val, gpc_base + GPC_PGC_ACK_SEL_A7); + } +} + +void imx_gpcv2_set_lpm_mode(enum mxc_cpu_pwr_mode mode) +{ + unsigned long flags; + u32 val1, val2; + + spin_lock_irqsave(&gpcv2_lock, flags); + + val1 = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC); + val2 = readl_relaxed(gpc_base + GPC_SLPCR); + + /* all cores' LPM settings must be same */ + val1 &= ~(BM_LPCR_A7_BSC_LPM0 | BM_LPCR_A7_BSC_LPM1); + + val1 |= BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + + val2 &= ~(BM_SLPCR_EN_DSM | BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | + BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY); + /* + * GPC: When improper low-power sequence is used, + * the SoC enters low power mode before the ARM core executes WFI. + * + * Software workaround: + * 1) Software should trigger IRQ #32 (IOMUX) to be always pending + * by setting IOMUX_GPR1_IRQ. + * 2) Software should then unmask IRQ #32 in GPC before setting GPC + * Low-Power mode. + * 3) Software should mask IRQ #32 right after GPC Low-Power mode + * is set. + */ + switch (mode) { + case WAIT_CLOCKED: + imx_gpcv2_hwirq_unmask(0); + break; + case WAIT_UNCLOCKED: + val1 |= A7_LPM_WAIT << BP_LPCR_A7_BSC_LPM0; + val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + imx_gpcv2_hwirq_mask(0); + break; + case STOP_POWER_ON: + val1 |= A7_LPM_STOP << BP_LPCR_A7_BSC_LPM0; + val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + val2 |= BM_SLPCR_EN_DSM; + val2 |= BM_SLPCR_RBC_EN; + val2 |= BM_SLPCR_BYPASS_PMIC_READY; + imx_gpcv2_hwirq_mask(0); + break; + case STOP_POWER_OFF: + val1 |= A7_LPM_STOP << BP_LPCR_A7_BSC_LPM0; + val1 &= ~BM_LPCR_A7_BSC_CPU_CLK_ON_LPM; + val2 |= BM_SLPCR_EN_DSM; + val2 |= BM_SLPCR_RBC_EN; + val2 |= BM_SLPCR_SBYOS; + val2 |= BM_SLPCR_VSTBY; + val2 |= BM_SLPCR_BYPASS_PMIC_READY; + imx_gpcv2_hwirq_mask(0); + break; + default: + return; + } + writel_relaxed(val1, gpc_base + GPC_LPCR_A7_BSC); + writel_relaxed(val2, gpc_base + GPC_SLPCR); + + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_plat_power_gate_by_lpm(bool pdn) +{ + u32 val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); + + val &= ~(BM_LPCR_A7_AD_EN_PLAT_PDN | BM_LPCR_A7_AD_L2PGE); + if (pdn) + val |= BM_LPCR_A7_AD_EN_PLAT_PDN | BM_LPCR_A7_AD_L2PGE; + + writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); +} + +void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset) +{ + writel_relaxed(enable, gpc_base + offset); +} + +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) +{ + u32 val = readl_relaxed(gpc_base + (pdn ? + GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)); + + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; + writel_relaxed(val, gpc_base + (pdn ? + GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)); + + while ((readl_relaxed(gpc_base + (pdn ? + GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)) & + BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0) + ; + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); +} + +void imx_gpcv2_set_cpu_power_gate_by_wfi(u32 cpu, bool pdn) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gpcv2_lock, flags); + val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); + + if (cpu == 0) { + if (pdn) { + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0); + val |= BM_LPCR_A7_AD_EN_C0_WFI_PDN | + BM_LPCR_A7_AD_EN_C0_IRQ_PUP; + } else { + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); + val &= ~(BM_LPCR_A7_AD_EN_C0_WFI_PDN | + BM_LPCR_A7_AD_EN_C0_IRQ_PUP); + } + } + if (cpu == 1) { + if (pdn) { + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); + val |= BM_LPCR_A7_AD_EN_C1_WFI_PDN | + BM_LPCR_A7_AD_EN_C1_IRQ_PUP; + } else { + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); + val &= ~(BM_LPCR_A7_AD_EN_C1_WFI_PDN | + BM_LPCR_A7_AD_EN_C1_IRQ_PUP); + } + } + writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_cpu_power_gate_by_lpm(u32 cpu, bool pdn) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gpcv2_lock, flags); + + val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); + if (cpu == 0) { + if (pdn) + val |= BM_LPCR_A7_AD_EN_C0_PDN | + BM_LPCR_A7_AD_EN_C0_PUP; + else + val &= ~(BM_LPCR_A7_AD_EN_C0_PDN | + BM_LPCR_A7_AD_EN_C0_PUP); + } + if (cpu == 1) { + if (pdn) + val |= BM_LPCR_A7_AD_EN_C1_PDN | + BM_LPCR_A7_AD_EN_C1_PUP; + else + val &= ~(BM_LPCR_A7_AD_EN_C1_PDN | + BM_LPCR_A7_AD_EN_C1_PUP); + } + + writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_cpu_power_gate_in_idle(bool pdn) +{ + unsigned long flags; + u32 cpu; + + for_each_possible_cpu(cpu) + imx_gpcv2_set_cpu_power_gate_by_lpm(cpu, pdn); + + spin_lock_irqsave(&gpcv2_lock, flags); + + imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C0); + if (num_online_cpus() > 1) + imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C1); + imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_SCU); + imx_gpcv2_set_plat_power_gate_by_lpm(pdn); + + if (pdn) { + imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false); + if (num_online_cpus() > 1) + imx_gpcv2_set_slot_ack(1, CORE1_A7, false, false); + imx_gpcv2_set_slot_ack(2, SCU_A7, false, true); + imx_gpcv2_set_slot_ack(6, SCU_A7, true, false); + imx_gpcv2_set_slot_ack(7, CORE0_A7, true, false); + if (num_online_cpus() > 1) + imx_gpcv2_set_slot_ack(8, CORE1_A7, true, true); + } else { + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 0 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 1 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 2 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 6 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 7 * 0x4); + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 8 * 0x4); + writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | + BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, + gpc_base + GPC_PGC_ACK_SEL_A7); + } + spin_unlock_irqrestore(&gpcv2_lock, flags); +} + +void imx_gpcv2_set_mix_phy_gate_by_lpm(u32 pdn_index, u32 pup_index) +{ + /* set power down slot */ + writel_relaxed(1 << (FAST_MEGA_MIX * 2), + gpc_base + GPC_SLOT0_CFG + pdn_index * 4); + + /* set power up slot */ + writel_relaxed(1 << (FAST_MEGA_MIX * 2 + 1), + gpc_base + GPC_SLOT0_CFG + pup_index * 4); +} + +unsigned int imx_gpcv2_is_mf_mix_off(void) +{ + return readl_relaxed(gpc_base + GPC_PGC_FM); +} + +static void imx_gpcv2_mf_mix_off(void) +{ + int i; + + for (i = 0; i < IMR_NUM; i++) + if (((gpcv2_wake_irqs[i] | gpcv2_mf_request_on[i]) & + gpcv2_mf_irqs[i]) != 0) + return; + + pr_info("Turn off Mega/Fast mix in DSM\n"); + imx_gpcv2_set_mix_phy_gate_by_lpm(1, 5); + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_FM); +} + +int imx_gpcv2_mf_power_on(unsigned int irq, unsigned int on) +{ + unsigned int idx = irq / 32 - 1; + unsigned long flags; + u32 mask; + + mask = 1 << (irq % 32); + spin_lock_irqsave(&gpcv2_lock, flags); + gpcv2_mf_request_on[idx] = on ? gpcv2_mf_request_on[idx] | mask : + gpcv2_mf_request_on[idx] & ~mask; + spin_unlock_irqrestore(&gpcv2_lock, flags); + + return 0; +} + +void imx_gpcv2_pre_suspend(bool arm_power_off) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + if (arm_power_off) { + imx_gpcv2_set_lpm_mode(STOP_POWER_OFF); + /* enable core0 power down/up with low power mode */ + imx_gpcv2_set_cpu_power_gate_by_lpm(0, true); + /* enable plat power down with low power mode */ + imx_gpcv2_set_plat_power_gate_by_lpm(true); + + /* + * To avoid confuse, we use slot 0~4 for power down, + * slot 5~9 for power up. + * + * Power down slot sequence: + * Slot0 -> CORE0 + * Slot1 -> Mega/Fast MIX + * Slot2 -> SCU + * + * Power up slot sequence: + * Slot5 -> Mega/Fast MIX + * Slot6 -> SCU + * Slot7 -> CORE0 + */ + imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false); + imx_gpcv2_set_slot_ack(2, SCU_A7, false, true); + + imx_gpcv2_mf_mix_off(); + + imx_gpcv2_set_slot_ack(6, SCU_A7, true, false); + imx_gpcv2_set_slot_ack(7, CORE0_A7, true, true); + + /* enable core0, scu */ + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0); + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_SCU); + } else { + imx_gpcv2_set_lpm_mode(STOP_POWER_ON); + } + + for (i = 0; i < IMR_NUM; i++) { + gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); + writel_relaxed(~gpcv2_wake_irqs[i], reg_imr1 + i * 4); + } +} + +void imx_gpcv2_post_resume(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; + int i; + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4); + + imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); + imx_gpcv2_set_cpu_power_gate_by_lpm(0, false); + imx_gpcv2_set_plat_power_gate_by_lpm(false); + + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_SCU); + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_FM); + for (i = 0; i < MAX_SLOT_NUMBER; i++) + writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + i * 0x4); + writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | + BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, + gpc_base + GPC_PGC_ACK_SEL_A7); +} + +static struct irq_chip imx_gpcv2_chip = { + .name = "GPCV2", + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = imx_gpcv2_irq_mask, + .irq_unmask = imx_gpcv2_irq_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_wake = imx_gpcv2_irq_set_wake, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif +}; + +static int imx_gpcv2_domain_xlate(struct irq_domain *domain, + struct device_node *controller, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (irq_domain_get_of_node(domain) != controller) + return -EINVAL; /* Shouldn't happen, really... */ + if (intsize != 3) + return -EINVAL; /* Not GIC compliant */ + if (intspec[0] != 0) + return -EINVAL; /* No PPI should point to this domain */ + + *out_hwirq = intspec[1]; + *out_type = intspec[2]; + return 0; +} + +static int imx_gpcv2_domain_alloc(struct irq_domain *domain, + unsigned int irq, + unsigned int nr_irqs, void *data) +{ + struct of_phandle_args *args = data; + struct of_phandle_args parent_args; + irq_hw_number_t hwirq; + int i; + + if (args->args_count != 3) + return -EINVAL; /* Not GIC compliant */ + if (args->args[0] != 0) + return -EINVAL; /* No PPI should point to this domain */ + + hwirq = args->args[1]; + if (hwirq >= GPC_MAX_IRQS) + return -EINVAL; /* Can't deal with this */ + + for (i = 0; i < nr_irqs; i++) + irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i, + &imx_gpcv2_chip, NULL); + + parent_args = *args; + parent_args.np = irq_domain_get_of_node(domain); + return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args); +} + +static struct irq_domain_ops imx_gpcv2_domain_ops = { + .xlate = imx_gpcv2_domain_xlate, + .alloc = imx_gpcv2_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int __init imx_gpcv2_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + int i, val; + + if (!parent) { + pr_err("%s: no parent, giving up\n", node->full_name); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("%s: unable to obtain parent domain\n", node->full_name); + return -ENXIO; + } + + gpc_base = of_iomap(node, 0); + if (WARN_ON(!gpc_base)) + return -ENOMEM; + + domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS, + node, &imx_gpcv2_domain_ops, + NULL); + if (!domain) { + iounmap(gpc_base); + return -ENOMEM; + } + + /* Initially mask all interrupts */ + for (i = 0; i < IMR_NUM; i++) { + writel_relaxed(~0, gpc_base + GPC_IMR1_CORE0 + i * 4); + writel_relaxed(~0, gpc_base + GPC_IMR1_CORE1 + i * 4); + } + /* + * Due to hardware design requirement, need to make sure GPR + * interrupt(#32) is unmasked during RUN mode to avoid entering + * DSM by mistake. + */ + writel_relaxed(~0x1, gpc_base + GPC_IMR1_CORE0); + + /* Read supported wakeup source in M/F domain */ + if (cpu_is_imx7d()) { + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0, + &gpcv2_mf_irqs[0]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1, + &gpcv2_mf_irqs[1]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 2, + &gpcv2_mf_irqs[2]); + of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 3, + &gpcv2_mf_irqs[3]); + if (!(gpcv2_mf_irqs[0] | gpcv2_mf_irqs[1] | + gpcv2_mf_irqs[2] | gpcv2_mf_irqs[3])) + pr_info("No wakeup source in Mega/Fast domain found!\n"); + } + + /* only external IRQs to wake up LPM and core 0/1 */ + val = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC); + val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP; + writel_relaxed(val, gpc_base + GPC_LPCR_A7_BSC); + /* mask m4 dsm trigger */ + writel_relaxed(readl_relaxed(gpc_base + GPC_LPCR_M4) | + BM_LPCR_M4_MASK_DSM_TRIGGER, gpc_base + GPC_LPCR_M4); + /* set mega/fast mix in A7 domain */ + writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_MAPPING); + /* set SCU timing */ + writel_relaxed((0x59 << 10) | 0x5B | (0x51 << 20), + gpc_base + GPC_PGC_SCU_TIMING); + writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | + BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, + gpc_base + GPC_PGC_ACK_SEL_A7); + + val = readl_relaxed(gpc_base + GPC_SLPCR); + val &= ~(BM_SLPCR_EN_DSM | BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | + BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY); + val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE; + writel_relaxed(val, gpc_base + GPC_SLPCR); + + /* disable memory low power mode */ + val = readl_relaxed(gpc_base + GPC_MLPCR); + val |= BM_GPC_MLPCR_MEMLP_CTL_DIS; + writel_relaxed(val, gpc_base + GPC_MLPCR); + + return 0; +} + +/* + * We cannot use the IRQCHIP_DECLARE macro that lives in + * drivers/irqchip, so we're forced to roll our own. Not very nice. + */ +OF_DECLARE_2(irqchip, imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_init); + +void __init imx_gpcv2_check_dt(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc"); + if (WARN_ON(!np)) + return; + + if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) { + pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); + + /* map GPC, so that at least CPUidle and WARs keep working */ + gpc_base = of_iomap(np, 0); + } +} + +static int imx_gpcv2_probe(struct platform_device *pdev) +{ + return 0; +} + +static struct of_device_id imx_gpcv2_dt_ids[] = { + { .compatible = "fsl,imx7d-gpc" }, + { } +}; + +static struct platform_driver imx_gpcv2_driver = { + .driver = { + .name = "imx-gpcv2", + .owner = THIS_MODULE, + .of_match_table = imx_gpcv2_dt_ids, + }, + .probe = imx_gpcv2_probe, +}; + +static int __init imx_pgcv2_init(void) +{ + return platform_driver_register(&imx_gpcv2_driver); +} +subsys_initcall(imx_pgcv2_init); diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 26ca744d3e2b12..003ef45b8d5210 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -104,6 +104,12 @@ static void __init imx7d_init_irq(void) irqchip_init(); } +static void __init imx7d_map_io(void) +{ + debug_ll_io_init(); + imx7_pm_map_io(); +} + static const char *const imx7d_dt_compat[] __initconst = { "fsl,imx7d", "fsl,imx7s", @@ -111,6 +117,7 @@ static const char *const imx7d_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") + .map_io = imx7d_map_io, .init_irq = imx7d_init_irq, .init_machine = imx7d_init_machine, .dt_compat = imx7d_dt_compat, diff --git a/arch/arm/mach-imx/pm-imx7.c b/arch/arm/mach-imx/pm-imx7.c new file mode 100644 index 00000000000000..02d167849e6011 --- /dev/null +++ b/arch/arm/mach-imx/pm-imx7.c @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "hardware.h" + +#define MX7_SUSPEND_OCRAM_SIZE 0x1000 +#define MX7_MAX_DDRC_NUM 32 +#define MX7_MAX_DDRC_PHY_NUM 16 + +#define MX7_SUSPEND_IRAM_ADDR_OFFSET 0 +#define READ_DATA_FROM_HARDWARE 0 + +#define UART_UCR1 0x80 +#define UART_UCR2 0x84 +#define UART_UCR3 0x88 +#define UART_UCR4 0x8c +#define UART_UFCR 0x90 +#define UART_UESC 0x9c +#define UART_UTIM 0xa0 +#define UART_UBIR 0xa4 +#define UART_UBMR 0xa8 +#define UART_UBRC 0xac +#define UART_UTS 0xb4 + +unsigned long iram_tlb_base_addr; +unsigned long iram_tlb_phys_addr; + +static unsigned int *ocram_saved_in_ddr; +static void __iomem *ocram_base; +static unsigned int ocram_size; +static void __iomem *ccm_base; +static void __iomem *console_base; +static void __iomem *suspend_ocram_base; +static void (*imx7_suspend_in_ocram_fn)(void __iomem *ocram_vbase); +/* + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx7_suspend code + * PM_INFO structure(imx7_cpu_pm_info) + * ======================== low address ======================= + */ + +struct imx7_pm_base { + phys_addr_t pbase; + void __iomem *vbase; +}; + +struct imx7_pm_socdata { + u32 ddr_type; + const char *ddrc_compat; + const char *src_compat; + const char *iomuxc_compat; + const char *gpc_compat; + const u32 ddrc_num; + const u32 (*ddrc_offset)[2]; + const u32 ddrc_phy_num; + const u32 (*ddrc_phy_offset)[2]; +}; + +static const u32 imx7d_ddrc_lpddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x1a0, READ_DATA_FROM_HARDWARE }, + { 0x1a4, READ_DATA_FROM_HARDWARE }, + { 0x1a8, READ_DATA_FROM_HARDWARE }, + { 0x64, READ_DATA_FROM_HARDWARE }, + { 0xd0, 0xc0350001 }, + { 0xdc, READ_DATA_FROM_HARDWARE }, + { 0xe0, READ_DATA_FROM_HARDWARE }, + { 0xe4, READ_DATA_FROM_HARDWARE }, + { 0xf4, READ_DATA_FROM_HARDWARE }, + { 0x100, READ_DATA_FROM_HARDWARE }, + { 0x104, READ_DATA_FROM_HARDWARE }, + { 0x108, READ_DATA_FROM_HARDWARE }, + { 0x10c, READ_DATA_FROM_HARDWARE }, + { 0x110, READ_DATA_FROM_HARDWARE }, + { 0x114, READ_DATA_FROM_HARDWARE }, + { 0x118, READ_DATA_FROM_HARDWARE }, + { 0x11c, READ_DATA_FROM_HARDWARE }, + { 0x180, READ_DATA_FROM_HARDWARE }, + { 0x184, READ_DATA_FROM_HARDWARE }, + { 0x190, READ_DATA_FROM_HARDWARE }, + { 0x194, READ_DATA_FROM_HARDWARE }, + { 0x200, READ_DATA_FROM_HARDWARE }, + { 0x204, READ_DATA_FROM_HARDWARE }, + { 0x214, READ_DATA_FROM_HARDWARE }, + { 0x218, READ_DATA_FROM_HARDWARE }, + { 0x240, 0x06000601 }, + { 0x244, READ_DATA_FROM_HARDWARE }, +}; + +static const u32 imx7d_ddrc_phy_lpddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x4, READ_DATA_FROM_HARDWARE }, + { 0x8, READ_DATA_FROM_HARDWARE }, + { 0x10, READ_DATA_FROM_HARDWARE }, + { 0x1c, READ_DATA_FROM_HARDWARE }, + { 0x9c, READ_DATA_FROM_HARDWARE }, + { 0x20, READ_DATA_FROM_HARDWARE }, + { 0x30, READ_DATA_FROM_HARDWARE }, + { 0x50, 0x01000008 }, + { 0x50, 0x00000008 }, + { 0xc0, 0x0e407304 }, + { 0xc0, 0x0e447304 }, + { 0xc0, 0x0e447306 }, + { 0xc0, 0x0e4c7304 }, + { 0xc0, 0x0e487306 }, +}; + +static const u32 imx7d_ddrc_ddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x1a0, READ_DATA_FROM_HARDWARE }, + { 0x1a4, READ_DATA_FROM_HARDWARE }, + { 0x1a8, READ_DATA_FROM_HARDWARE }, + { 0x64, READ_DATA_FROM_HARDWARE }, + { 0x490, 0x00000001 }, + { 0xd0, 0xc0020001 }, + { 0xd4, READ_DATA_FROM_HARDWARE }, + { 0xdc, READ_DATA_FROM_HARDWARE }, + { 0xe0, READ_DATA_FROM_HARDWARE }, + { 0xe4, READ_DATA_FROM_HARDWARE }, + { 0xf4, READ_DATA_FROM_HARDWARE }, + { 0x100, READ_DATA_FROM_HARDWARE }, + { 0x104, READ_DATA_FROM_HARDWARE }, + { 0x108, READ_DATA_FROM_HARDWARE }, + { 0x10c, READ_DATA_FROM_HARDWARE }, + { 0x110, READ_DATA_FROM_HARDWARE }, + { 0x114, READ_DATA_FROM_HARDWARE }, + { 0x120, 0x03030803 }, + { 0x180, READ_DATA_FROM_HARDWARE }, + { 0x190, READ_DATA_FROM_HARDWARE }, + { 0x194, READ_DATA_FROM_HARDWARE }, + { 0x200, READ_DATA_FROM_HARDWARE }, + { 0x204, READ_DATA_FROM_HARDWARE }, + { 0x214, READ_DATA_FROM_HARDWARE }, + { 0x218, READ_DATA_FROM_HARDWARE }, + { 0x240, 0x06000601 }, + { 0x244, READ_DATA_FROM_HARDWARE }, +}; + +static const u32 imx7d_ddrc_phy_ddr3_setting[][2] __initconst = { + { 0x0, READ_DATA_FROM_HARDWARE }, + { 0x4, READ_DATA_FROM_HARDWARE }, + { 0x10, READ_DATA_FROM_HARDWARE }, + { 0x9c, READ_DATA_FROM_HARDWARE }, + { 0x20, READ_DATA_FROM_HARDWARE }, + { 0x30, READ_DATA_FROM_HARDWARE }, + { 0x50, 0x01000010 }, + { 0x50, 0x00000010 }, + { 0xc0, 0x0e407304 }, + { 0xc0, 0x0e447304 }, + { 0xc0, 0x0e447306 }, + { 0xc0, 0x0e447304 }, + { 0xc0, 0x0e407306 }, +}; + +static const struct imx7_pm_socdata imx7d_pm_data_lpddr3 __initconst = { + .ddrc_compat = "fsl,imx7d-ddrc", + .src_compat = "fsl,imx7d-src", + .iomuxc_compat = "fsl,imx7d-iomuxc", + .gpc_compat = "fsl,imx7d-gpc", + .ddrc_num = ARRAY_SIZE(imx7d_ddrc_lpddr3_setting), + .ddrc_offset = imx7d_ddrc_lpddr3_setting, + .ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_lpddr3_setting), + .ddrc_phy_offset = imx7d_ddrc_phy_lpddr3_setting, +}; + +static const struct imx7_pm_socdata imx7d_pm_data_ddr3 __initconst = { + .ddrc_compat = "fsl,imx7d-ddrc", + .src_compat = "fsl,imx7d-src", + .iomuxc_compat = "fsl,imx7d-iomuxc", + .gpc_compat = "fsl,imx7d-gpc", + .ddrc_num = ARRAY_SIZE(imx7d_ddrc_ddr3_setting), + .ddrc_offset = imx7d_ddrc_ddr3_setting, + .ddrc_phy_num = ARRAY_SIZE(imx7d_ddrc_phy_ddr3_setting), + .ddrc_phy_offset = imx7d_ddrc_phy_ddr3_setting, +}; + +/* + * This structure is for passing necessary data for low level ocram + * suspend code(arch/arm/mach-imx/suspend-imx7.S), if this struct + * definition is changed, the offset definition in + * arch/arm/mach-imx/suspend-imx7.S must be also changed accordingly, + * otherwise, the suspend to ocram function will be broken! + */ +struct imx7_cpu_pm_info { + u32 m4_reserve0; + u32 m4_reserve1; + u32 m4_reserve2; + phys_addr_t pbase; /* The physical address of pm_info. */ + phys_addr_t resume_addr; /* The physical resume address for asm code */ + u32 ddr_type; + u32 pm_info_size; /* Size of pm_info. */ + struct imx7_pm_base ddrc_base; + struct imx7_pm_base ddrc_phy_base; + struct imx7_pm_base src_base; + struct imx7_pm_base iomuxc_gpr_base; + struct imx7_pm_base ccm_base; + struct imx7_pm_base gpc_base; + struct imx7_pm_base l2_base; + struct imx7_pm_base anatop_base; + u32 ttbr1; /* Store TTBR1 */ + u32 ddrc_num; /* Number of DDRC which need saved/restored. */ + u32 ddrc_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */ + u32 ddrc_phy_num; /* Number of DDRC which need saved/restored. */ + u32 ddrc_phy_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */ +} __aligned(8); + +static struct map_desc imx7_pm_io_desc[] __initdata = { + imx_map_entry(MX7D, AIPS1, MT_DEVICE), + imx_map_entry(MX7D, AIPS2, MT_DEVICE), + imx_map_entry(MX7D, AIPS3, MT_DEVICE), +}; + +static const char * const low_power_ocram_match[] __initconst = { + "fsl,lpm-sram", + NULL +}; + +static void imx7_console_save(unsigned int *regs) +{ + if (!console_base) + return; + + regs[0] = readl_relaxed(console_base + UART_UCR1); + regs[1] = readl_relaxed(console_base + UART_UCR2); + regs[2] = readl_relaxed(console_base + UART_UCR3); + regs[3] = readl_relaxed(console_base + UART_UCR4); + regs[4] = readl_relaxed(console_base + UART_UFCR); + regs[5] = readl_relaxed(console_base + UART_UESC); + regs[6] = readl_relaxed(console_base + UART_UTIM); + regs[7] = readl_relaxed(console_base + UART_UBIR); + regs[8] = readl_relaxed(console_base + UART_UBMR); + regs[9] = readl_relaxed(console_base + UART_UTS); +} + +static void imx7_console_restore(unsigned int *regs) +{ + if (!console_base) + return; + + writel_relaxed(regs[4], console_base + UART_UFCR); + writel_relaxed(regs[5], console_base + UART_UESC); + writel_relaxed(regs[6], console_base + UART_UTIM); + writel_relaxed(regs[7], console_base + UART_UBIR); + writel_relaxed(regs[8], console_base + UART_UBMR); + writel_relaxed(regs[9], console_base + UART_UTS); + writel_relaxed(regs[0], console_base + UART_UCR1); + writel_relaxed(regs[1] | 0x1, console_base + UART_UCR2); + writel_relaxed(regs[2], console_base + UART_UCR3); + writel_relaxed(regs[3], console_base + UART_UCR4); +} + +static int imx7_suspend_finish(unsigned long val) +{ + if (!imx7_suspend_in_ocram_fn) { + cpu_do_idle(); + } else { + /* + * call low level suspend function in ocram, + * as we need to float DDR IO. + */ + local_flush_tlb_all(); + imx7_suspend_in_ocram_fn(suspend_ocram_base); + } + + return 0; +} + +static int imx7_pm_enter(suspend_state_t state) +{ + unsigned int console_saved_reg[10] = {0}; + + if (!iram_tlb_base_addr) { + pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \ + code. Please ensure device tree has an entry for \ + fsl,lpm-sram.\n"); + return -EINVAL; + } + + switch (state) { + case PM_SUSPEND_STANDBY: + imx_anatop_pre_suspend(); + imx_gpcv2_pre_suspend(false); + + /* Zzz ... */ + imx7_suspend_in_ocram_fn(suspend_ocram_base); + + imx_anatop_post_resume(); + imx_gpcv2_post_resume(); + break; + case PM_SUSPEND_MEM: + imx_anatop_pre_suspend(); + imx_gpcv2_pre_suspend(true); + if (imx_gpcv2_is_mf_mix_off()) { + imx7_console_save(console_saved_reg); + memcpy(ocram_saved_in_ddr, ocram_base, ocram_size); + } + + /* Zzz ... */ + cpu_suspend(0, imx7_suspend_finish); + + if (imx_gpcv2_is_mf_mix_off()) { + memcpy(ocram_base, ocram_saved_in_ddr, ocram_size); + imx7_console_restore(console_saved_reg); + } + imx_anatop_post_resume(); + imx_gpcv2_post_resume(); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int imx7_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM; +} + +static const struct platform_suspend_ops imx7_pm_ops = { + .enter = imx7_pm_enter, + .valid = imx7_pm_valid, +}; + +void __init imx7_pm_set_ccm_base(void __iomem *base) +{ + ccm_base = base; +} + +static struct map_desc iram_tlb_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_1M, + .type = MT_MEMORY_RWX_NONCACHED, +}; + +static int __init imx7_dt_find_lpsram(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned long lpram_addr; + const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL); + + if (of_flat_dt_match(node, low_power_ocram_match)) { + if (!prop) + return -EINVAL; + + lpram_addr = be32_to_cpup(prop); + + /* We need to create a 1M page table entry. */ + iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000); + iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000); + iram_tlb_phys_addr = lpram_addr; + iram_tlb_base_addr = IMX_IO_P2V(lpram_addr); + iotable_init(&iram_tlb_io_desc, 1); + } + + return 0; +} + +void __init imx7_pm_map_io(void) +{ + unsigned long i, j; + + iotable_init(imx7_pm_io_desc, ARRAY_SIZE(imx7_pm_io_desc)); + /* + * Get the address of IRAM or OCRAM to be used by the low + * power code from the device tree. + */ + WARN_ON(of_scan_flat_dt(imx7_dt_find_lpsram, NULL)); + + /* Return if no IRAM space is allocated for suspend/resume code. */ + if (!iram_tlb_base_addr) { + pr_warn("No valid ocram available for suspend/resume!\n"); + return; + } + + /* Set all entries to 0. */ + memset((void *)iram_tlb_base_addr, 0, MX7_IRAM_TLB_SIZE); + + /* + * Make sure the IRAM virtual address has a mapping in the IRAM + * page table. + * + * Only use the top 12 bits [31-20] when storing the physical + * address in the page table as only these bits are required + * for 1M mapping. + */ + j = ((iram_tlb_base_addr >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS1 virtual address has a mapping in the + * IRAM page table. + */ + for (i = 0; i < 4; i++) { + j = ((IMX_IO_P2V(MX7D_AIPS1_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7D_AIPS1_BASE_ADDR + i * 0x100000) & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } + + /* + * Make sure the AIPS2 virtual address has a mapping in the + * IRAM page table. + */ + for (i = 0; i < 4; i++) { + j = ((IMX_IO_P2V(MX7D_AIPS2_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7D_AIPS2_BASE_ADDR + i * 0x100000) & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } + + /* + * Make sure the AIPS3 virtual address has a mapping + * in the IRAM page table. + */ + for (i = 0; i < 4; i++) { + j = ((IMX_IO_P2V(MX7D_AIPS3_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + j) = + ((MX7D_AIPS3_BASE_ADDR + i * 0x100000) & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + } +} + +static int __init imx7_suspend_init(const struct imx7_pm_socdata *socdata) +{ + struct device_node *node; + struct imx7_cpu_pm_info *pm_info; + int i, ret = 0; + const u32 (*ddrc_offset_array)[2]; + const u32 (*ddrc_phy_offset_array)[2]; + unsigned long iram_paddr; + + suspend_set_ops(&imx7_pm_ops); + + if (!socdata) { + pr_warn("%s: invalid argument!\n", __func__); + return -EINVAL; + } + + /* + * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, + * The lower 8K is not used, so use the lower 8K for IRAM code and + * pm_info. + * + */ + iram_paddr = iram_tlb_phys_addr + MX7_SUSPEND_IRAM_ADDR_OFFSET; + + /* Make sure iram_paddr is 8 byte aligned. */ + if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1)) + iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN); + + /* Get the virtual address of the suspend code. */ + suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr); + + pm_info = suspend_ocram_base; + /* pbase points to iram_paddr. */ + pm_info->pbase = iram_paddr; + pm_info->resume_addr = virt_to_phys(ca7_cpu_resume); + pm_info->pm_info_size = sizeof(*pm_info); + + /* + * ccm physical address is not used by asm code currently, + * so get ccm virtual address directly, as we already have + * it from ccm driver. + */ + pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR; + pm_info->ccm_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_CCM_BASE_ADDR); + + pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR; + pm_info->ddrc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_DDRC_BASE_ADDR); + + pm_info->ddrc_phy_base.pbase = MX7D_DDRC_PHY_BASE_ADDR; + pm_info->ddrc_phy_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR); + + pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR; + pm_info->src_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_SRC_BASE_ADDR); + + pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR; + pm_info->iomuxc_gpr_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR); + + pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR; + pm_info->gpc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_GPC_BASE_ADDR); + + pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR; + pm_info->anatop_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR); + + pm_info->ddrc_num = socdata->ddrc_num; + ddrc_offset_array = socdata->ddrc_offset; + pm_info->ddrc_phy_num = socdata->ddrc_phy_num; + ddrc_phy_offset_array = socdata->ddrc_phy_offset; + + /* initialize DDRC settings */ + for (i = 0; i < pm_info->ddrc_num; i++) { + pm_info->ddrc_val[i][0] = ddrc_offset_array[i][0]; + if (ddrc_offset_array[i][1] == READ_DATA_FROM_HARDWARE) + pm_info->ddrc_val[i][1] = + readl_relaxed(pm_info->ddrc_base.vbase + + ddrc_offset_array[i][0]); + else + pm_info->ddrc_val[i][1] = ddrc_offset_array[i][1]; + } + + /* initialize DDRC PHY settings */ + for (i = 0; i < pm_info->ddrc_phy_num; i++) { + pm_info->ddrc_phy_val[i][0] = + ddrc_phy_offset_array[i][0]; + if (ddrc_phy_offset_array[i][1] == READ_DATA_FROM_HARDWARE) + pm_info->ddrc_phy_val[i][1] = + readl_relaxed(pm_info->ddrc_phy_base.vbase + + ddrc_phy_offset_array[i][0]); + else + pm_info->ddrc_phy_val[i][1] = + ddrc_phy_offset_array[i][1]; + } + + imx7_suspend_in_ocram_fn = fncpy( + suspend_ocram_base + sizeof(*pm_info), + &imx7_suspend, + MX7_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); + + goto put_node; + +put_node: + of_node_put(node); + + return ret; +} + +static void __init imx7_pm_common_init(const struct imx7_pm_socdata + *socdata) +{ + int ret; + struct regmap *gpr; + + if (IS_ENABLED(CONFIG_SUSPEND)) { + ret = imx7_suspend_init(socdata); + if (ret) + pr_warn("%s: No DDR LPM support with suspend %d!\n", + __func__, ret); + } + + /* + * Force IOMUXC irq pending, so that the interrupt to GPC can be + * used to deassert dsm_request signal when the signal gets + * asserted unexpectedly. + */ + gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_IRQ_MASK, + IMX7D_GPR1_IRQ_MASK); +} + +void __init imx7d_pm_init(void) +{ + struct device_node *np; + struct resource res; + + if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR3) + imx7_pm_common_init(&imx7d_pm_data_lpddr3); + else if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_DDR3) + imx7_pm_common_init(&imx7d_pm_data_ddr3); + + np = of_find_compatible_node(NULL, NULL, "fsl,mega-fast-sram"); + ocram_base = of_iomap(np, 0); + WARN_ON(!ocram_base); + WARN_ON(of_address_to_resource(np, 0, &res)); + ocram_size = resource_size(&res); + ocram_saved_in_ddr = kzalloc(ocram_size, GFP_KERNEL); + WARN_ON(!ocram_saved_in_ddr); + + np = of_find_node_by_path( + "/soc/aips-bus@30800000/spba-bus@30800000/serial@30860000"); + if (np) + console_base = of_iomap(np, 0); +} diff --git a/arch/arm/mach-imx/suspend-imx7.S b/arch/arm/mach-imx/suspend-imx7.S new file mode 100644 index 00000000000000..3cc0dc5bebc89a --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx7.S @@ -0,0 +1,567 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include "hardware.h" + +/* + * ==================== low level suspend ==================== + * + * Better to follow below rules to use ARM registers: + * r0: pm_info structure address; + * r1 ~ r4: for saving pm_info members; + * r5 ~ r10: free registers; + * r11: io base address. + * + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx7_suspend code + * PM_INFO structure(imx7_cpu_pm_info) + * ======================== low address ======================= + */ + +/* + * Below offsets are based on struct imx7_cpu_pm_info + * which defined in arch/arm/mach-imx/pm-imx7.c, this + * structure contains necessary pm info for low level + * suspend related code. + */ +#define PM_INFO_M4_RESERVE0_OFFSET 0x0 +#define PM_INFO_M4_RESERVE1_OFFSET 0x4 +#define PM_INFO_M4_RESERVE2_OFFSET 0x8 +#define PM_INFO_PBASE_OFFSET 0xc +#define PM_INFO_RESUME_ADDR_OFFSET 0x10 +#define PM_INFO_DDR_TYPE_OFFSET 0x14 +#define PM_INFO_PM_INFO_SIZE_OFFSET 0x18 +#define PM_INFO_MX7_DDRC_P_OFFSET 0x1c +#define PM_INFO_MX7_DDRC_V_OFFSET 0x20 +#define PM_INFO_MX7_DDRC_PHY_P_OFFSET 0x24 +#define PM_INFO_MX7_DDRC_PHY_V_OFFSET 0x28 +#define PM_INFO_MX7_SRC_P_OFFSET 0x2c +#define PM_INFO_MX7_SRC_V_OFFSET 0x30 +#define PM_INFO_MX7_IOMUXC_GPR_P_OFFSET 0x34 +#define PM_INFO_MX7_IOMUXC_GPR_V_OFFSET 0x38 +#define PM_INFO_MX7_CCM_P_OFFSET 0x3c +#define PM_INFO_MX7_CCM_V_OFFSET 0x40 +#define PM_INFO_MX7_GPC_P_OFFSET 0x44 +#define PM_INFO_MX7_GPC_V_OFFSET 0x48 +#define PM_INFO_MX7_L2_P_OFFSET 0x4c +#define PM_INFO_MX7_L2_V_OFFSET 0x50 +#define PM_INFO_MX7_ANATOP_P_OFFSET 0x54 +#define PM_INFO_MX7_ANATOP_V_OFFSET 0x58 +#define PM_INFO_MX7_TTBR1_V_OFFSET 0x5c +#define PM_INFO_DDRC_REG_NUM_OFFSET 0x60 +#define PM_INFO_DDRC_REG_OFFSET 0x64 +#define PM_INFO_DDRC_VALUE_OFFSET 0x68 +#define PM_INFO_DDRC_PHY_REG_NUM_OFFSET 0x164 +#define PM_INFO_DDRC_PHY_REG_OFFSET 0x168 +#define PM_INFO_DDRC_PHY_VALUE_OFFSET 0x16c + +#define MX7_SRC_GPR1 0x74 +#define MX7_SRC_GPR2 0x78 +#define GPC_PGC_C0 0x800 +#define GPC_PGC_FM 0xa00 +#define ANADIG_SNVS_MISC_CTRL 0x380 +#define DDRC_STAT 0x4 +#define DDRC_PWRCTL 0x30 +#define DDRC_PSTAT 0x3fc +#define DDRC_PCTRL_0 0x490 +#define DDRC_DFIMISC 0x1b0 +#define DDRC_SWCTL 0x320 +#define DDRC_SWSTAT 0x324 +#define DDRPHY_LP_CON0 0x18 + + .align 3 + + .macro disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + .endm + + .macro store_ttbr1 + + /* Store TTBR1 to pm_info->ttbr1 */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_MX7_TTBR1_V_OFFSET] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r6, [r6] + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r6, c2, c0, 1 + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + .endm + + .macro restore_ttbr1 + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Restore TTBCR */ + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Restore TTBR1, get the origin ttbr1 from pm info */ + ldr r7, [r0, #PM_INFO_MX7_TTBR1_V_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + + .macro ddrc_enter_self_refresh + + ldr r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r11, #DDRC_PWRCTL] + + /* wait rw port_busy clear */ + ldr r6, =(0x1 << 16) + orr r6, r6, #0x1 +1: + ldr r7, [r11, #DDRC_PSTAT] + ands r7, r7, r6 + bne 1b + + /* enter self-refresh bit 5 */ + ldr r7, =(0x1 << 5) + str r7, [r11, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +2: + ldr r7, [r11, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 2b +3: + ldr r7, [r11, #DDRC_STAT] + ands r7, r7, #0x20 + beq 3b + + /* disable dram clk */ + ldr r7, [r11, #DDRC_PWRCTL] + orr r7, r7, #(1 << 3) + str r7, [r11, #DDRC_PWRCTL] + + .endm + + .macro ddrc_exit_self_refresh + + cmp r5, #0x0 + ldreq r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + ldrne r11, [r0, #PM_INFO_MX7_DDRC_P_OFFSET] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r11, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +4: + ldr r7, [r11, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + beq 4b + + /* enable auto self-refresh */ + ldr r7, [r11, #DDRC_PWRCTL] + orr r7, r7, #(1 << 0) + str r7, [r11, #DDRC_PWRCTL] + + .endm + + .macro wait_delay +5: + subs r6, r6, #0x1 + bne 5b + + .endm + + .macro ddr_enter_retention + + ldr r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r11, #DDRC_PCTRL_0] + + /* wait rw port_busy clear */ + ldr r6, =(0x1 << 16) + orr r6, r6, #0x1 +6: + ldr r7, [r11, #DDRC_PSTAT] + ands r7, r7, r6 + bne 6b + + ldr r11, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + /* enter self-refresh bit 5 */ + ldr r7, =(0x1 << 5) + str r7, [r11, #DDRC_PWRCTL] + + /* wait until self-refresh mode entered */ +7: + ldr r7, [r11, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 7b +8: + ldr r7, [r11, #DDRC_STAT] + ands r7, r7, #0x20 + beq 8b + + /* disable dram clk */ + ldr r7, =(0x1 << 5) + orr r7, r7, #(1 << 3) + str r7, [r11, #DDRC_PWRCTL] + + /* reset ddr_phy */ + ldr r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldr r7, =0x0 + str r7, [r11, #ANADIG_SNVS_MISC_CTRL] + + /* delay 7 us */ + ldr r6, =6000 + wait_delay + + ldr r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + ldr r6, =0x1000 + ldr r7, [r11, r6] + orr r7, r7, #0x1 + str r7, [r11, r6] + /* turn off ddr power */ + ldr r11, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldr r7, =(0x1 << 29) + str r7, [r11, #ANADIG_SNVS_MISC_CTRL] + + .endm + + .macro ddr_exit_retention + + cmp r5, #0x0 + ldreq r1, [r0, #PM_INFO_MX7_ANATOP_V_OFFSET] + ldrne r1, [r0, #PM_INFO_MX7_ANATOP_P_OFFSET] + ldreq r2, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + ldrne r2, [r0, #PM_INFO_MX7_SRC_P_OFFSET] + ldreq r3, [r0, #PM_INFO_MX7_DDRC_V_OFFSET] + ldrne r3, [r0, #PM_INFO_MX7_DDRC_P_OFFSET] + ldreq r4, [r0, #PM_INFO_MX7_DDRC_PHY_V_OFFSET] + ldrne r4, [r0, #PM_INFO_MX7_DDRC_PHY_P_OFFSET] + ldreq r10, [r0, #PM_INFO_MX7_CCM_V_OFFSET] + ldrne r10, [r0, #PM_INFO_MX7_CCM_P_OFFSET] + ldreq r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_V_OFFSET] + ldrne r11, [r0, #PM_INFO_MX7_IOMUXC_GPR_P_OFFSET] + + /* turn on ddr power */ + ldr r7, =(0x1 << 29) + str r7, [r1, #ANADIG_SNVS_MISC_CTRL] + + ldr r6, =50 + wait_delay + + ldr r7, =0x0 + str r7, [r1, #ANADIG_SNVS_MISC_CTRL] + + /* clear ddr_phy reset */ + ldr r6, =0x1000 + ldr r7, [r2, r6] + orr r7, r7, #0x3 + str r7, [r2, r6] + ldr r7, [r2, r6] + bic r7, r7, #0x1 + str r7, [r2, r6] + + ldr r6, [r0, #PM_INFO_DDRC_REG_NUM_OFFSET] + ldr r7, =PM_INFO_DDRC_REG_OFFSET + add r7, r7, r0 +9: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r3, r8] + subs r6, r6, #0x1 + bne 9b + ldr r7, =0x20 + str r7, [r3, #DDRC_PWRCTL] + ldr r7, =0x0 + str r7, [r3, #DDRC_DFIMISC] + + /* do PHY, clear ddr_phy reset */ + ldr r6, =0x1000 + ldr r7, [r2, r6] + bic r7, r7, #0x2 + str r7, [r2, r6] + + ldr r7, =(0x1 << 30) + str r7, [r1, #ANADIG_SNVS_MISC_CTRL] + + /* need to delay ~5mS */ + ldr r6, =0x100000 + wait_delay + + ldr r6, [r0, #PM_INFO_DDRC_PHY_REG_NUM_OFFSET] + ldr r7, =PM_INFO_DDRC_PHY_REG_OFFSET + add r7, r7, r0 + +10: + ldr r8, [r7], #0x4 + ldr r9, [r7], #0x4 + str r9, [r4, r8] + subs r6, r6, #0x1 + bne 10b + + ldr r7, =0x0 + add r9, r10, #0x4000 + str r7, [r9, #0x130] + + ldr r7, =0x170 + orr r7, r7, #0x8 + str r7, [r11, #0x20] + + ldr r7, =0x2 + add r9, r10, #0x4000 + str r7, [r9, #0x130] + + ldr r7, =0xf + str r7, [r4, #DDRPHY_LP_CON0] + + /* wait until self-refresh mode entered */ +11: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x3 + bne 11b + ldr r7, =0x0 + str r7, [r3, #DDRC_SWCTL] + ldr r7, =0x1 + str r7, [r3, #DDRC_DFIMISC] + ldr r7, =0x1 + str r7, [r3, #DDRC_SWCTL] +12: + ldr r7, [r3, #DDRC_SWSTAT] + and r7, r7, #0x1 + cmp r7, #0x1 + bne 12b +13: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x20 + cmp r7, #0x20 + bne 13b + + /* let DDR out of self-refresh */ + ldr r7, =0x0 + str r7, [r3, #DDRC_PWRCTL] +14: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x30 + cmp r7, #0x0 + bne 14b + +15: + ldr r7, [r3, #DDRC_STAT] + and r7, r7, #0x3 + cmp r7, #0x1 + bne 15b + + /* enable port */ + ldr r7, =0x1 + str r7, [r3, #DDRC_PCTRL_0] + + .endm + +ENTRY(imx7_suspend) + push {r4-r12} + + /* check whether it is a standby mode */ + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_C0] + cmp r7, #0 + beq ddr_only_self_refresh + + /* + * The value of r0 is mapped the same in origin table and IRAM table, + * thus no need to care r0 here. + */ + ldr r1, [r0, #PM_INFO_PBASE_OFFSET] + ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] + ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] + + /* + * counting the resume address in iram + * to set it in SRC register. + */ + ldr r6, =imx7_suspend + ldr r7, =resume + sub r7, r7, r6 + add r8, r1, r4 + add r9, r8, r7 + + ldr r11, [r0, #PM_INFO_MX7_SRC_V_OFFSET] + /* store physical resume addr and pm_info address. */ + str r9, [r11, #MX7_SRC_GPR1] + str r1, [r11, #MX7_SRC_GPR2] + + disable_l1_dcache + + store_ttbr1 + + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_FM] + cmp r7, #0 + beq ddr_only_self_refresh + + ddr_enter_retention + b ddr_retention_enter_out +ddr_only_self_refresh: + ddrc_enter_self_refresh +ddr_retention_enter_out: + + /* Zzz, enter stop mode */ + wfi + nop + nop + nop + nop + + mov r5, #0x0 + + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_FM] + cmp r7, #0 + beq wfi_ddr_self_refresh_out + + ddr_exit_retention + b wfi_ddr_retention_out +wfi_ddr_self_refresh_out: + ddrc_exit_self_refresh +wfi_ddr_retention_out: + + /* check whether it is a standby mode */ + ldr r11, [r0, #PM_INFO_MX7_GPC_V_OFFSET] + ldr r7, [r11, #GPC_PGC_C0] + cmp r7, #0 + beq standby_out + + restore_ttbr1 +standby_out: + pop {r4-r12} + /* return to suspend finish */ + mov pc, lr + +resume: + /* invalidate L1 I-cache first */ + mov r6, #0x0 + mcr p15, 0, r6, c7, c5, 0 + mcr p15, 0, r6, c7, c5, 6 + /* enable the Icache and branch prediction */ + mov r6, #0x1800 + mcr p15, 0, r6, c1, c0, 0 + isb + + /* get physical resume address from pm_info. */ + ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] + /* clear core0's entry and parameter */ + ldr r11, [r0, #PM_INFO_MX7_SRC_P_OFFSET] + mov r7, #0x0 + str r7, [r11, #MX7_SRC_GPR1] + str r7, [r11, #MX7_SRC_GPR2] + + mov r5, #0x1 + + ldr r11, [r0, #PM_INFO_MX7_GPC_P_OFFSET] + ldr r7, [r11, #GPC_PGC_FM] + cmp r7, #0 + beq dsm_ddr_self_refresh_out + + ddr_exit_retention + b dsm_ddr_retention_out +dsm_ddr_self_refresh_out: + ddrc_exit_self_refresh +dsm_ddr_retention_out: + + mov pc, lr +ENDPROC(imx7_suspend) + +ENTRY(ca7_cpu_resume) + bl v7_invalidate_l1 + b cpu_resume +ENDPROC(ca7_cpu_resume) From d95776fab057ffb752bdec4c4a9f07f0d277dab5 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 27 Oct 2016 15:33:59 +0300 Subject: [PATCH 0007/3047] MLK-11265-7 ARM: imx: add smp support for imx7d Add SMP support for i.MX7D, including CPU hotplug support. Signed-off-by: Anson Huang --- arch/arm/mach-imx/headsmp.S | 13 ++++++- arch/arm/mach-imx/hotplug.c | 5 ++- arch/arm/mach-imx/mach-imx7d.c | 1 + arch/arm/mach-imx/platsmp.c | 38 +++++++++++++++--- arch/arm/mach-imx/src.c | 70 +++++++++++++++++++++++++--------- 5 files changed, 103 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 6c28d28b3c6479..5d6a5e2fe9eee7 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -27,6 +27,17 @@ diag_reg_offset: ENTRY(v7_secondary_startup) ARM_BE8(setend be) @ go BE8 if entered LE + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =0xf00 + orr r1, r1, #0xff + mov r0, r0, lsr #4 + and r0, r0, r1 + /* 0xc07 is cortex A7's ID */ + ldr r1, =0xc00 + orr r1, r1, #0x7 + cmp r0, r1 + beq secondary_startup + set_diag_reg b secondary_startup ENDPROC(v7_secondary_startup) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index b35e99cc5e5b4f..06dab2fc1c252a 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -16,6 +16,7 @@ #include #include "common.h" +#include "hardware.h" static inline void cpu_enter_lowpower(void) { @@ -66,5 +67,7 @@ int imx_cpu_kill(unsigned int cpu) return 0; imx_enable_cpu(cpu, false); imx_set_cpu_arg(cpu, 0); + if (cpu_is_imx7d()) + imx_gpcv2_set_core1_pdn_pup_by_software(true); return 1; } diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 003ef45b8d5210..8b9b8cbfae3055 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -118,6 +118,7 @@ static const char *const imx7d_dt_compat[] __initconst = { DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") .map_io = imx7d_map_io, + .smp = smp_ops(imx_smp_ops), .init_irq = imx7d_init_irq, .init_machine = imx7d_init_machine, .dt_compat = imx7d_dt_compat, diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 711dbbd5baddaa..8ec0a278a9c5c1 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -24,7 +24,7 @@ #include "hardware.h" u32 g_diag_reg; -static void __iomem *scu_base; +static void __iomem *imx_scu_base; static struct map_desc scu_io_desc __initdata = { /* .virtual and .pfn are run-time assigned */ @@ -43,7 +43,7 @@ void __init imx_scu_map_io(void) scu_io_desc.pfn = __phys_to_pfn(base); iotable_init(&scu_io_desc, 1); - scu_base = IMX_IO_ADDRESS(base); + imx_scu_base = IMX_IO_ADDRESS(base); } static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -53,15 +53,39 @@ static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle) return 0; } +#define MXC_ARCH_CA7 0xc07 +static unsigned long __mxc_arch_type; + +static inline bool arm_is_ca7(void) +{ + return __mxc_arch_type == MXC_ARCH_CA7; +} /* * Initialise the CPU possible map early - this describes the CPUs * which may be present or become present in the system. */ static void __init imx_smp_init_cpus(void) { + unsigned long arch_type; int i, ncores; - ncores = scu_get_core_count(scu_base); + asm volatile( + ".align 4\n" + "mrc p15, 0, %0, c0, c0, 0\n" + : "=r" (arch_type) + ); + /* MIDR[15:4] defines ARCH type */ + __mxc_arch_type = (arch_type >> 4) & 0xfff; + + if (arm_is_ca7()) { + unsigned long val; + + /* CA7 core number, [25:24] of CP15 L2CTLR */ + asm volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (val)); + ncores = ((val >> 24) & 0x3) + 1; + } else { + ncores = scu_get_core_count(imx_scu_base); + } for (i = ncores; i < NR_CPUS; i++) set_cpu_possible(i, false); @@ -69,11 +93,15 @@ static void __init imx_smp_init_cpus(void) void imx_smp_prepare(void) { - scu_enable(scu_base); + if (arm_is_ca7()) + return; + scu_enable(imx_scu_base); } static void __init imx_smp_prepare_cpus(unsigned int max_cpus) { + if (arm_is_ca7()) + return; imx_smp_prepare(); /* diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 70b083fe934a8f..f09821356e5133 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -18,6 +18,7 @@ #include #include #include "common.h" +#include "hardware.h" #define SRC_SCR 0x000 #define SRC_GPR1 0x020 @@ -29,9 +30,16 @@ #define BP_SRC_SCR_SW_IPU2_RST 12 #define BP_SRC_SCR_CORE1_RST 14 #define BP_SRC_SCR_CORE1_ENABLE 22 +/* below is for i.MX7D */ +#define SRC_GPR1_V2 0x074 +#define SRC_A7RCR0 0x004 +#define SRC_A7RCR1 0x008 + +#define BP_SRC_A7RCR0_A7_CORE_RESET0 0 +#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1 static void __iomem *src_base; -static DEFINE_SPINLOCK(scr_lock); +static DEFINE_SPINLOCK(src_lock); static const int sw_reset_bits[5] = { BP_SRC_SCR_SW_GPU_RST, @@ -57,11 +65,11 @@ static int imx_src_reset_module(struct reset_controller_dev *rcdev, bit = 1 << sw_reset_bits[sw_reset_idx]; - spin_lock_irqsave(&scr_lock, flags); + spin_lock_irqsave(&src_lock, flags); val = readl_relaxed(src_base + SRC_SCR); val |= bit; writel_relaxed(val, src_base + SRC_SCR); - spin_unlock_irqrestore(&scr_lock, flags); + spin_unlock_irqrestore(&src_lock, flags); timeout = jiffies + msecs_to_jiffies(1000); while (readl(src_base + SRC_SCR) & bit) { @@ -87,32 +95,57 @@ void imx_enable_cpu(int cpu, bool enable) u32 mask, val; cpu = cpu_logical_map(cpu); - mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); - spin_lock(&scr_lock); - val = readl_relaxed(src_base + SRC_SCR); - val = enable ? val | mask : val & ~mask; - val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); - writel_relaxed(val, src_base + SRC_SCR); - spin_unlock(&scr_lock); + spin_lock(&src_lock); + if (cpu_is_imx7d()) { + /* enable core */ + if (enable) + imx_gpcv2_set_core1_pdn_pup_by_software(false); + + mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_A7RCR1); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_A7RCR1); + } else { + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); + writel_relaxed(val, src_base + SRC_SCR); + } + spin_unlock(&src_lock); } void imx_set_cpu_jump(int cpu, void *jump_addr) { cpu = cpu_logical_map(cpu); - writel_relaxed(virt_to_phys(jump_addr), - src_base + SRC_GPR1 + cpu * 8); + if (cpu_is_imx7d()) + writel_relaxed(virt_to_phys(jump_addr), + src_base + SRC_GPR1_V2 + cpu * 8); + else + writel_relaxed(virt_to_phys(jump_addr), + src_base + SRC_GPR1 + cpu * 8); } u32 imx_get_cpu_arg(int cpu) { cpu = cpu_logical_map(cpu); - return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); + if (cpu_is_imx7d()) + return readl_relaxed(src_base + SRC_GPR1_V2 + + cpu * 8 + 4); + else + return readl_relaxed(src_base + SRC_GPR1 + + cpu * 8 + 4); } void imx_set_cpu_arg(int cpu, u32 arg) { cpu = cpu_logical_map(cpu); - writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); + if (cpu_is_imx7d()) + writel_relaxed(arg, src_base + SRC_GPR1_V2 + + cpu * 8 + 4); + else + writel_relaxed(arg, src_base + SRC_GPR1 + + cpu * 8 + 4); } void __init imx_src_init(void) @@ -126,6 +159,9 @@ void __init imx_src_init(void) src_base = of_iomap(np, 0); WARN_ON(!src_base); + if (cpu_is_imx7d()) + return; + imx_reset_controller.of_node = np; if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) reset_controller_register(&imx_reset_controller); @@ -134,9 +170,9 @@ void __init imx_src_init(void) * force warm reset sources to generate cold reset * for a more reliable restart */ - spin_lock(&scr_lock); + spin_lock(&src_lock); val = readl_relaxed(src_base + SRC_SCR); val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); writel_relaxed(val, src_base + SRC_SCR); - spin_unlock(&scr_lock); + spin_unlock(&src_lock); } From acf073967936f6c47a65fce5a3cf45edac4e97a1 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 20 Jul 2015 17:00:16 +0800 Subject: [PATCH 0008/3047] MLK-11265-10 ARM: configs: add imx v7 support Add imx_v7_defconfig and imx_v7_mfg_defconfig support for V7 only. Signed-off-by: Anson Huang Signed-off-by: Peng Fan --- arch/arm/configs/imx_v7_defconfig | 416 ++++++++++++++++++++++++++ arch/arm/configs/imx_v7_mfg_defconfig | 333 +++++++++++++++++++++ 2 files changed, 749 insertions(+) create mode 100644 arch/arm/configs/imx_v7_defconfig create mode 100644 arch/arm/configs/imx_v7_mfg_defconfig diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig new file mode 100644 index 00000000000000..8779126f41f720 --- /dev/null +++ b/arch/arm/configs/imx_v7_defconfig @@ -0,0 +1,416 @@ +CONFIG_KERNEL_LZO=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_MULTI_V6=y +CONFIG_GPIO_PCA953X=y +CONFIG_ARCH_MXC=y +# CONFIG_MACH_MX31ADS is not set +# CONFIG_MACH_BUG is not set +CONFIG_MACH_IMX51_DT=y +CONFIG_MACH_EUKREA_CPUIMX51SD=y +CONFIG_SOC_IMX50=y +CONFIG_SOC_IMX53=y +CONFIG_SOC_IMX6Q=y +CONFIG_SOC_IMX6SL=y +CONFIG_SOC_IMX6SX=y +CONFIG_SOC_VF610=y +# CONFIG_SWP_EMULATE is not set +CONFIG_SMP=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_VMSPLIT_2G=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_ARM_IMX6Q_CPUFREQ=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_BINFMT_MISC=m +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_PM_TEST_SUSPEND=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_VLAN_8021Q=y +CONFIG_LLC2=y +CONFIG_CAN=y +CONFIG_CAN_FLEXCAN=y +CONFIG_CAN_M_CAN=y +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIBTUSB=y +CONFIG_BT_HCIBTSDIO=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIBCM203X=y +CONFIG_BT_ATH3K=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=320 +CONFIG_IMX_WEIM=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SST25L=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_GPMI_NAND=y +CONFIG_MTD_NAND_MXC=y +CONFIG_MTD_SPI_NOR=y +CONFIG_SPI_FSL_QUADSPI=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_IMX=y +CONFIG_PATA_IMX=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +CONFIG_CS89x0=y +CONFIG_CS89x0_PLATFORM=y +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_ATH_CARDS=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_BRCMFMAC=m +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_SNVS_PWRKEY=y +CONFIG_KEYBOARD_IMX=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_EGALAX=y +CONFIG_TOUCHSCREEN_ELAN=y +CONFIG_TOUCHSCREEN_MAX11801=y +CONFIG_TOUCHSCREEN_MC13783=y +CONFIG_TOUCHSCREEN_TSC2007=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MMA8450=y +CONFIG_INPUT_ISL29023=y +CONFIG_SERIO_SERPORT=m +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_FSL_OTP=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_IMX=y +CONFIG_SPI=y +CONFIG_SPI_IMX=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_SUPPLY=y +CONFIG_SABRESD_MAX8903=y +CONFIG_SENSORS_MAX17135=y +CONFIG_SENSORS_MAG3110=y +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_IMX_THERMAL=y +CONFIG_DEVICE_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_IMX2_WDT=y +CONFIG_MFD_DA9052_I2C=y +CONFIG_MFD_MC13XXX_SPI=y +CONFIG_MFD_MC13XXX_I2C=y +CONFIG_MFD_MAX17135=y +CONFIG_MFD_SI476X_CORE=y +CONFIG_MFD_STMPE=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_ANATOP=y +CONFIG_REGULATOR_DA9052=y +CONFIG_REGULATOR_MAX17135=y +CONFIG_REGULATOR_MC13783=y +CONFIG_REGULATOR_MC13892=y +CONFIG_REGULATOR_PFUZE100=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_RC_DEVICES=y +CONFIG_IR_GPIO_CIR=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_MXC_OUTPUT=y +CONFIG_VIDEO_MXC_CAPTURE=m +CONFIG_MXC_CAMERA_OV5640=m +CONFIG_MXC_CAMERA_OV5642=m +CONFIG_MXC_CAMERA_OV5640_MIPI=m +CONFIG_MXC_TVIN_ADV7180=m +CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m +CONFIG_VIDEO_MXC_IPU_OUTPUT=y +CONFIG_VIDEO_MXC_PXP_V4L2=y +CONFIG_VIDEO_MXC_CSI_CAMERA=m +CONFIG_MXC_VADC=m +CONFIG_SOC_CAMERA=y +CONFIG_VIDEO_MX3=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CODA=y +CONFIG_RADIO_SI476X=y +CONFIG_SOC_CAMERA_OV2640=y +CONFIG_DRM=y +CONFIG_DRM_VIVANTE=y +CONFIG_FB=y +CONFIG_FB_MXS=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_L4F00242T03=y +CONFIG_LCD_PLATFORM=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_FB_MXC_SYNC_PANEL=y +CONFIG_FB_MXC_LDB=y +CONFIG_FB_MXC_MIPI_DSI=y +CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y +CONFIG_FB_MXC_HDMI=y +CONFIG_FB_MXC_EINK_PANEL=y +CONFIG_FB_MXS_SII902X=y +CONFIG_FB_MXC_DCIC=m +CONFIG_HANNSTAR_CABC=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_SOC=y +CONFIG_SND_IMX_SOC=y +CONFIG_SND_SOC_EUKREA_TLV320=y +CONFIG_SND_SOC_IMX_CS42888=y +CONFIG_SND_SOC_IMX_WM8962=y +CONFIG_SND_SOC_IMX_SGTL5000=y +CONFIG_SND_SOC_IMX_MQS=y +CONFIG_SND_SOC_IMX_SPDIF=y +CONFIG_SND_SOC_IMX_MC13783=y +CONFIG_SND_SOC_IMX_HDMI=y +CONFIG_SND_SOC_IMX_SI476X=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MXC=y +CONFIG_USB_ACM=m +CONFIG_USB_STORAGE=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_EHSET_TEST_FIXTURE=m +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MXS_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_LB_SS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_ESDHC_IMX=y +CONFIG_MXC_IPU=y +CONFIG_MXC_GPU_VIV=y +CONFIG_MXC_MIPI_CSI2=y +CONFIG_MXC_MLB150=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_MC13XXX=y +CONFIG_RTC_DRV_MXC=y +CONFIG_RTC_DRV_SNVS=y +CONFIG_DMADEVICES=y +CONFIG_MXC_PXP_V2=y +CONFIG_IMX_SDMA=y +CONFIG_MXS_DMA=y +CONFIG_STAGING=y +CONFIG_STAGING_MEDIA=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_IIO=y +CONFIG_VF610_ADC=y +CONFIG_PWM=y +CONFIG_PWM_IMX=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_UTF8=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FTRACE is not set +CONFIG_SECURITYFS=y +CONFIG_CRYPTO_USER=y +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_LRW=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRYPTO_RMD128=y +CONFIG_CRYPTO_RMD160=y +CONFIG_CRYPTO_RMD256=y +CONFIG_CRYPTO_RMD320=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_TGR192=y +CONFIG_CRYPTO_WP512=y +CONFIG_CRYPTO_BLOWFISH=y +CONFIG_CRYPTO_CAMELLIA=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_TWOFISH=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=y +CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y diff --git a/arch/arm/configs/imx_v7_mfg_defconfig b/arch/arm/configs/imx_v7_mfg_defconfig new file mode 100644 index 00000000000000..347db61fa6448b --- /dev/null +++ b/arch/arm/configs/imx_v7_mfg_defconfig @@ -0,0 +1,333 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_LZO=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PERF_EVENTS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_ARCH_MULTI_V6=y +CONFIG_GPIO_PCA953X=y +CONFIG_ARCH_MXC=y +# CONFIG_MACH_MX31ADS is not set +# CONFIG_MACH_BUG is not set +CONFIG_MACH_IMX51_DT=y +CONFIG_MACH_EUKREA_CPUIMX51SD=y +CONFIG_SOC_IMX50=y +CONFIG_SOC_IMX53=y +CONFIG_SOC_IMX6Q=y +CONFIG_SOC_IMX6SL=y +CONFIG_SOC_IMX6SX=y +CONFIG_SOC_VF610=y +CONFIG_SMP=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_VMSPLIT_2G=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_ARM_IMX6Q_CPUFREQ=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_BINFMT_MISC=m +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_PM_TEST_SUSPEND=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_NETFILTER=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=320 +CONFIG_IMX_WEIM=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SST25L=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_GPMI_NAND=y +CONFIG_MTD_NAND_MXC=y +CONFIG_MTD_SPI_NOR=y +CONFIG_SPI_FSL_QUADSPI=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_IMX=y +CONFIG_PATA_IMX=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +CONFIG_CS89x0=y +CONFIG_CS89x0_PLATFORM=y +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_AT803X_PHY=y +CONFIG_BRCMFMAC=m +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_IMX=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_EGALAX=y +CONFIG_TOUCHSCREEN_MC13783=y +CONFIG_TOUCHSCREEN_TSC2007=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MMA8450=y +CONFIG_SERIO_SERPORT=m +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_IMX_SEMA4=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_IMX=y +CONFIG_SPI=y +CONFIG_SPI_IMX=y +CONFIG_GPIO_SYSFS=y +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_IMX_THERMAL=y +CONFIG_DEVICE_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_IMX2_WDT=y +CONFIG_MFD_DA9052_I2C=y +CONFIG_MFD_MC13XXX_SPI=y +CONFIG_MFD_MC13XXX_I2C=y +CONFIG_MFD_STMPE=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_ANATOP=y +CONFIG_REGULATOR_DA9052=y +CONFIG_REGULATOR_MC13783=y +CONFIG_REGULATOR_MC13892=y +CONFIG_REGULATOR_PFUZE100=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_RC_DEVICES=y +CONFIG_IR_GPIO_CIR=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_MXC_OUTPUT=y +CONFIG_VIDEO_MXC_IPU_OUTPUT=y +CONFIG_VIDEO_MXC_PXP_V4L2=y +CONFIG_SOC_CAMERA=y +CONFIG_VIDEO_MX3=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CODA=y +CONFIG_SOC_CAMERA_OV2640=y +CONFIG_DRM=y +CONFIG_DRM_VIVANTE=y +CONFIG_FB=y +CONFIG_FB_MXS=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_L4F00242T03=y +CONFIG_LCD_PLATFORM=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_FB_MXC_SYNC_PANEL=y +CONFIG_FB_MXC_LDB=y +CONFIG_FB_MXC_MIPI_DSI=y +CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y +CONFIG_FB_MXC_HDMI=y +CONFIG_FB_MXC_EINK_PANEL=y +CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE=y +CONFIG_FB_MXS_SII902X=y +CONFIG_HANNSTAR_CABC=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_IMX_SOC=y +CONFIG_SND_SOC_EUKREA_TLV320=y +CONFIG_SND_SOC_IMX_WM8962=y +CONFIG_SND_SOC_IMX_SGTL5000=y +CONFIG_SND_SOC_IMX_SPDIF=y +CONFIG_SND_SOC_IMX_MC13783=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MXC=y +CONFIG_USB_STORAGE=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MXS_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=m +CONFIG_USB_PHY=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +CONFIG_USB_MASS_STORAGE=y +CONFIG_FSL_UTP=y +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_ESDHC_IMX=y +CONFIG_MXC_IPU=y +CONFIG_MXC_GPU_VIV=y +CONFIG_MXC_MIPI_CSI2=y +CONFIG_MXC_MLB150=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_MC13XXX=y +CONFIG_RTC_DRV_MXC=y +CONFIG_RTC_DRV_SNVS=y +CONFIG_DMADEVICES=y +CONFIG_MXC_PXP_V2=y +CONFIG_IMX_SDMA=y +CONFIG_MXS_DMA=y +CONFIG_STAGING=y +CONFIG_STAGING_MEDIA=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_PWM=y +CONFIG_PWM_IMX=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_UTF8=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FTRACE is not set +CONFIG_SECURITYFS=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_HW is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=m +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y From 00b0869c8c539cc409bc4ea76778c1a403ed1675 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 22 Jul 2015 10:40:07 +0800 Subject: [PATCH 0009/3047] MLK-11265-11 ARM: configs: enable imx7d soc support by default Enable CONFIG_SOC_IMX7D by default. Signed-off-by: Anson Huang --- arch/arm/configs/imx_v7_defconfig | 1 + arch/arm/configs/imx_v7_mfg_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 8779126f41f720..d3d9316571a9d0 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -28,6 +28,7 @@ CONFIG_SOC_IMX53=y CONFIG_SOC_IMX6Q=y CONFIG_SOC_IMX6SL=y CONFIG_SOC_IMX6SX=y +CONFIG_SOC_IMX7D=y CONFIG_SOC_VF610=y # CONFIG_SWP_EMULATE is not set CONFIG_SMP=y diff --git a/arch/arm/configs/imx_v7_mfg_defconfig b/arch/arm/configs/imx_v7_mfg_defconfig index 347db61fa6448b..f813e2625b934c 100644 --- a/arch/arm/configs/imx_v7_mfg_defconfig +++ b/arch/arm/configs/imx_v7_mfg_defconfig @@ -29,6 +29,7 @@ CONFIG_SOC_IMX53=y CONFIG_SOC_IMX6Q=y CONFIG_SOC_IMX6SL=y CONFIG_SOC_IMX6SX=y +CONFIG_SOC_IMX7D=y CONFIG_SOC_VF610=y CONFIG_SMP=y CONFIG_HAVE_ARM_ARCH_TIMER=y From 68310c96a1f4b236de2dd51115e053a5b6762a31 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 15 Sep 2014 11:20:58 +0800 Subject: [PATCH 0010/3047] MLK-11285-01 net: fec: handle WAIT mode issue for imx6qdl This is a combination of commits 919d46e37e04 (ENGR00265935 net: fec: add pm_qos to avoid cpu enter to wait mode) and 8a12c90c9974 (ENGR00313685-14 net: fec: check workaround for FEC_QUIRK_BUG_WAITMODE) from imx_3.10.y branch. It's added for imx_3.14.y branch to work around imx6qdl issue ERR006687 (ENET: Only the ENET wake-up interrupt request can wake the system from Wait mode). Signed-off-by: Shawn Guo (cherry-pick and merge from commit: 4f406fae257cc7945a0e3a425213440bb12ba345) --- drivers/net/ethernet/freescale/fec.h | 8 ++++++ drivers/net/ethernet/freescale/fec_main.c | 31 ++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 5ea740b4cf14c9..a6a977bb13450f 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -446,6 +447,12 @@ struct bufdesc_ex { #define FEC_QUIRK_HAS_COALESCE (1 << 13) /* Interrupt doesn't wake CPU from deep idle */ #define FEC_QUIRK_ERR006687 (1 << 14) +/* + * i.MX6Q/DL ENET cannot wake up system in wait mode because ENET tx & rx + * interrupt signal don't connect to GPC. So use pm qos to avoid cpu enter + * to wait mode. + */ +#define FEC_QUIRK_BUG_WAITMODE (1 << 15) struct bufdesc_prop { int qid; @@ -553,6 +560,7 @@ struct fec_enet_private { int hwts_tx_en; struct delayed_work time_keep; struct regulator *reg_phy; + struct pm_qos_request pm_qos_req; unsigned int tx_align; unsigned int rx_align; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 91709187125953..c0dc643d9ad015 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -102,7 +102,7 @@ static struct platform_device_id fec_devtype[] = { .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | - FEC_QUIRK_HAS_RACC, + FEC_QUIRK_HAS_RACC | FEC_QUIRK_BUG_WAITMODE, }, { .name = "mvf600-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, @@ -2828,10 +2828,29 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) return 0; } +static inline bool fec_enet_irq_workaround(struct fec_enet_private *fep) +{ + struct device_node *np = fep->pdev->dev.of_node; + struct device_node *intr_node; + + intr_node = of_parse_phandle(np, "interrupts-extended", 0); + if (intr_node && !strcmp(intr_node->name, "gpio")) { + /* + * If the interrupt controller is a GPIO node, it must have + * applied the workaround for WAIT mode bug. + */ + return true; + } + + return false; +} + static int fec_enet_open(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); int ret; ret = pm_runtime_get_sync(&fep->pdev->dev); @@ -2866,6 +2885,16 @@ fec_enet_open(struct net_device *ndev) phy_start(ndev->phydev); netif_tx_start_all_queues(ndev); + if ((id_entry->driver_data & FEC_QUIRK_BUG_WAITMODE) && + !fec_enet_irq_workaround(fep)) + pm_qos_add_request(&fep->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + 0); + else + pm_qos_add_request(&fep->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + device_set_wakeup_enable(&ndev->dev, fep->wol_flag & FEC_WOL_FLAG_ENABLE); From d86f8b02886d69e64ded8c8ca982597a4df0df90 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 10 Oct 2014 16:25:26 +0800 Subject: [PATCH 0011/3047] MLK-11285-02 net:fec: add enet AVB Ubuntu Gstreamer demo support Support Gstreamer AVB demo support. ring1 -> ClassA, ring2 -> ClassB, ring0 -> Best Effort For QoS: ring1 > ring2 > ring0 For bandwidth reverse: 50% bandwidth -> ClassA 33% bandwidth -> ClassB 17% bandwidth -> Best effort queue In general, ClassA run audio, ClassB run video. Since AVB demo use big bandwidth streaming, video cost more than 33Mbps bandwidth, and with Qos limitation: ClassA >= ClassB > Best effort, so we have to change ring2 bandwidth equal to ring1 bandwidth (50%). After validate on FPGA, AVB demo can work fine for audio and video. Signed-off-by: Fugang Duan (cherry picked from commit 93d6579a7b3d2dafa721c835df5d5f7d30ed386e) --- drivers/net/ethernet/freescale/fec_main.c | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index c0dc643d9ad015..eb88a3d6ed488d 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -18,7 +18,7 @@ * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. * - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. */ #include @@ -72,6 +72,7 @@ static void fec_enet_itr_coal_init(struct net_device *ndev); #define DRIVER_NAME "fec" #define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0)) +static const u16 fec_enet_vlan_pri_to_queue[8] = {1, 1, 1, 1, 2, 2, 2, 2}; /* Pause frame feild and FIFO threshold */ #define FEC_ENET_FCE (1 << 5) @@ -3102,10 +3103,42 @@ static int fec_set_features(struct net_device *netdev, return 0; } +u16 fec_enet_get_raw_vlan_tci(struct sk_buff *skb) +{ + struct vlan_ethhdr *vhdr; + unsigned short vlan_TCI = 0; + + if (skb->protocol == ntohs(ETH_P_ALL)) { + vhdr = (struct vlan_ethhdr *)(skb->data); + vlan_TCI = ntohs(vhdr->h_vlan_TCI); + } + + return vlan_TCI; +} + +u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + u16 vlan_tag; + + if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB)) + return skb_tx_hash(ndev, skb); + + vlan_tag = fec_enet_get_raw_vlan_tci(skb); + if (!vlan_tag) + return vlan_tag; + + return fec_enet_vlan_pri_to_queue[vlan_tag >> 13]; +} + static const struct net_device_ops fec_netdev_ops = { .ndo_open = fec_enet_open, .ndo_stop = fec_enet_close, .ndo_start_xmit = fec_enet_start_xmit, + .ndo_select_queue = fec_enet_select_queue, .ndo_set_rx_mode = set_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, From 426652ef08b80f2c7f2a182c2b102fa08b600357 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 14 Oct 2014 16:44:57 +0800 Subject: [PATCH 0012/3047] MLK-9691 net: fec: call .pm_qos_remove_request() in .ndo_stop() callback Call .pm_qos_remove_request() in .ndo_stop() callback to avoid kernel warning during enet open/close test. Signed-off-by: Fugang Duan (cherry picked from commit: f81c176d36b8189220a729d723801d2cdd495108) --- drivers/net/ethernet/freescale/fec_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index eb88a3d6ed488d..0cbf188bc64479 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2933,6 +2933,7 @@ fec_enet_close(struct net_device *ndev) fec_enet_update_ethtool_stats(ndev); fec_enet_clk_enable(ndev, false); + pm_qos_remove_request(&fep->pm_qos_req); pinctrl_pm_select_sleep_state(&fep->pdev->dev); pm_runtime_mark_last_busy(&fep->pdev->dev); pm_runtime_put_autosuspend(&fep->pdev->dev); From 6ef311981861fe97effcbf18bb988beb61d57180 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 10 Dec 2014 13:46:08 +0800 Subject: [PATCH 0013/3047] MLK-9919 net: fec: reinit MAC0 MII bus for MAC1 use after resume back i.MX6SX-AI board has two enet MACs (MAC0 and MAC1), they share MAC0 MII bus. When PHY0 don't connect to enet MAC0, MAC0 mii bus probe phy0 failed, and the net interface is set to unattach mode. During suspend resume test, driver don't reinit MAC0 after resume back, so MII bus don't work that causes MAC1 also cannot access PHY1. The patch just is workaround that reinit MAC0 MII bus for MAC1 using. Signed-off-by: Fugang Duan (cherry picked from commit: b730adeef4f9b44e302c793cbef35ea74f24fbef) --- drivers/net/ethernet/freescale/fec.h | 5 ++++ drivers/net/ethernet/freescale/fec_main.c | 34 +++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index a6a977bb13450f..4f3f5e9c4a9d0e 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -354,6 +354,8 @@ struct bufdesc_ex { #define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) #define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) +#define FEC0_MII_BUS_SHARE_TRUE 1 + /* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ #define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ @@ -379,6 +381,8 @@ struct bufdesc_ex { #define FEC_NAPI_IMASK (FEC_ENET_MII | FEC_ENET_TS_TIMER) #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) +#define FEC_ENET_ETHEREN ((uint)0x00000002) + /* ENET interrupt coalescing macro define */ #define FEC_ITR_CLK_SEL (0x1 << 30) #define FEC_ITR_EN (0x1 << 31) @@ -529,6 +533,7 @@ struct fec_enet_private { /* Phylib and MDIO interface */ struct mii_bus *mii_bus; int mii_timeout; + int mii_bus_share; uint phy_speed; phy_interface_t phy_interface; struct device_node *phy_node; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 0cbf188bc64479..2580f113b1fd6b 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -905,7 +905,7 @@ fec_restart(struct net_device *ndev) u32 val; u32 temp_mac[2]; u32 rcntl = OPT_FRAME_SIZE | 0x04; - u32 ecntl = 0x2; /* ETHEREN */ + u32 ecntl = FEC_ENET_ETHEREN; /* ETHEREN */ /* Whack a reset. We should wait for this. * For i.MX6SX SOC, enet use AXI bus, we use disable MAC @@ -1899,6 +1899,17 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) return ret; } +static void fec_restore_mii_bus(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + fec_enet_clk_enable(ndev, true); + writel(0xffc00000, fep->hwp + FEC_IEVENT); + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); + writel(FEC_ENET_ETHEREN, fep->hwp + FEC_ECNTRL); +} + static int fec_enet_mii_probe(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -1966,6 +1977,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) static int fec_enet_mii_init(struct platform_device *pdev) { static struct mii_bus *fec0_mii_bus; + static int *fec_mii_bus_share; struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); struct device_node *node; @@ -1988,10 +2000,11 @@ static int fec_enet_mii_init(struct platform_device *pdev) * mdio interface in board design, and need to be configured by * fec0 mii_bus. */ - if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) { + if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { /* fec1 uses fec0 mii_bus */ if (mii_cnt && fec0_mii_bus) { fep->mii_bus = fec0_mii_bus; + *fec_mii_bus_share = FEC0_MII_BUS_SHARE_TRUE; mii_cnt++; return 0; } @@ -2065,8 +2078,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) mii_cnt++; /* save fec0 mii_bus */ - if (fep->quirks & FEC_QUIRK_SINGLE_MDIO) + if (fep->quirks & FEC_QUIRK_ENET_MAC) { fec0_mii_bus = fep->mii_bus; + fec_mii_bus_share = &fep->mii_bus_share; + } return 0; @@ -2904,11 +2919,13 @@ fec_enet_open(struct net_device *ndev) err_enet_mii_probe: fec_enet_free_buffers(ndev); err_enet_alloc: - fec_enet_clk_enable(ndev, false); + if (!fep->mii_bus_share) + fec_enet_clk_enable(ndev, false); clk_enable: pm_runtime_mark_last_busy(&fep->pdev->dev); pm_runtime_put_autosuspend(&fep->pdev->dev); - pinctrl_pm_select_sleep_state(&fep->pdev->dev); + if (!fep->mii_bus_share) + pinctrl_pm_select_sleep_state(&fep->pdev->dev); return ret; } @@ -3612,6 +3629,10 @@ static int __maybe_unused fec_suspend(struct device *dev) fec_enet_clk_enable(ndev, false); if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) pinctrl_pm_select_sleep_state(&fep->pdev->dev); + pinctrl_pm_select_sleep_state(&fep->pdev->dev); + } else if (fep->mii_bus_share && !ndev->phydev) { + fec_enet_clk_enable(ndev, false); + pinctrl_pm_select_sleep_state(&fep->pdev->dev); } rtnl_unlock(); @@ -3664,6 +3685,9 @@ static int __maybe_unused fec_resume(struct device *dev) netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); phy_start(ndev->phydev); + } else if (fep->mii_bus_share && !ndev->phydev) { + pinctrl_pm_select_default_state(&fep->pdev->dev); + fec_restore_mii_bus(ndev); } rtnl_unlock(); From 4f002f4b3f97480d6d2c358e52fd80890e590877 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 23 Apr 2015 19:04:10 +0800 Subject: [PATCH 0014/3047] MLK-10724-6 net: fec: add i.mx6ul enet support i.MX6UL enet is the lite edition of i.MX6Q enet, don't support Gbps mode. Signed-off-by: Fugang Duan (cherry picked from commit: 32a2c3878322d8322a29c52af18de7707134ca1c) --- drivers/net/ethernet/freescale/fec_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 2580f113b1fd6b..335d8017a88806 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -120,6 +120,11 @@ static struct platform_device_id fec_devtype[] = { FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE, + }, { + .name = "imx6ul-fec", + .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | + FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | + FEC_QUIRK_HAS_VLAN, }, { /* sentinel */ } From 9467d72cc498e6f517ffadd12450bc7326f69790 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 20 May 2015 18:36:19 +0800 Subject: [PATCH 0015/3047] MLK-10939-01 net: fec: add stop mode support for dts register set The current driver support stop mode by calling machine api. The patch add dts support to set gpr register for stop request. After magic pattern comming during system suspend status, system will be waked up, and irq handler will be running, there have enet register access. Since all clocks are disabled in suspend, and clocks are enabled after resume function. But irq handler run before resume function. For imx7d chip, access register need some clocks enabled, otherwise system hang. So the patch also disable wake up irq in the suspend, after resume back enable the irq, which can avoid system hang issue. Signed-off-by: Fugang Duan (cherry pick and merge from commit: 8da4f80af0913781a4f9d50917c1dd66180e519d) --- .../devicetree/bindings/net/fsl-fec.txt | 3 + drivers/net/ethernet/freescale/fec.h | 9 ++ drivers/net/ethernet/freescale/fec_main.c | 94 +++++++++++++++---- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt index a1e3693cca1601..775ec4eb2f6a5e 100644 --- a/Documentation/devicetree/bindings/net/fsl-fec.txt +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt @@ -30,6 +30,9 @@ Optional properties: - fsl,err006687-workaround-present: If present indicates that the system has the hardware workaround for ERR006687 applied and does not need a software workaround. +- fsl,wakeup_irq : The property define the wakeup irq index in enet irq source. +- stop-mode : If present, indicates soc need to set gpr bit to request stop + mode. Optional subnodes: - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 4f3f5e9c4a9d0e..c9a16caf541b1d 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -471,6 +471,12 @@ struct bufdesc_prop { unsigned char dsize_log2; }; +struct fec_enet_stop_mode { + struct regmap *gpr; + u8 req_gpr; + u8 req_bit; +}; + struct fec_enet_priv_tx_q { struct bufdesc_prop bd; unsigned char *tx_bounce[TX_RING_SIZE]; @@ -545,6 +551,7 @@ struct fec_enet_private { bool bufdesc_ex; int pause_flag; int wol_flag; + int wake_irq; u32 quirks; struct napi_struct napi; @@ -589,6 +596,8 @@ struct fec_enet_private { unsigned int next_counter; u64 ethtool_stats[0]; + + struct fec_enet_stop_mode gpr; }; void fec_ptp_init(struct platform_device *pdev); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 335d8017a88806..48fd750f5ac44f 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include @@ -1087,11 +1089,30 @@ fec_restart(struct net_device *ndev) } +static int fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled) +{ + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; + + if (fep->gpr.gpr) { + if (enabled) + regmap_update_bits(fep->gpr.gpr, fep->gpr.req_gpr, + 1 << fep->gpr.req_bit, + 1 << fep->gpr.req_bit); + else + regmap_update_bits(fep->gpr.gpr, fep->gpr.req_gpr, + 1 << fep->gpr.req_bit, + 0); + } else if (pdata && pdata->sleep_mode_enable) { + pdata->sleep_mode_enable(enabled); + } + + return 0; +} + static void fec_stop(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - struct fec_platform_data *pdata = fep->pdev->dev.platform_data; u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); u32 val; @@ -1121,8 +1142,7 @@ fec_stop(struct net_device *ndev) val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); writel(val, fep->hwp + FEC_ECNTRL); - if (pdata && pdata->sleep_mode_enable) - pdata->sleep_mode_enable(true); + fec_enet_stop_mode(fep, true); } writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -2586,15 +2606,10 @@ fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) return -EINVAL; device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC); - if (device_may_wakeup(&ndev->dev)) { + if (device_may_wakeup(&ndev->dev)) fep->wol_flag |= FEC_WOL_FLAG_ENABLE; - if (fep->irq[0] > 0) - enable_irq_wake(fep->irq[0]); - } else { + else fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE); - if (fep->irq[0] > 0) - disable_irq_wake(fep->irq[0]); - } return 0; } @@ -3371,6 +3386,41 @@ fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx) } +static void fec_enet_of_parse_stop_mode(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + struct fec_enet_private *fep = netdev_priv(dev); + struct device_node *node; + phandle phandle; + u32 out_val[3]; + int ret; + + ret = of_property_read_u32_array(np, "stop-mode", out_val, 3); + if (ret) { + dev_dbg(&pdev->dev, "no stop-mode property\n"); + return; + } + + phandle = *out_val; + node = of_find_node_by_phandle(phandle); + if (!node) { + dev_dbg(&pdev->dev, "could not find gpr node by phandle\n"); + return; + } + + fep->gpr.gpr = syscon_node_to_regmap(node); + if (IS_ERR(fep->gpr.gpr)) { + dev_dbg(&pdev->dev, "could not find gpr regmap\n"); + return; + } + + of_node_put(node); + + fep->gpr.req_gpr = out_val[1]; + fep->gpr.req_bit = out_val[2]; +} + static int fec_probe(struct platform_device *pdev) { @@ -3433,6 +3483,8 @@ fec_probe(struct platform_device *pdev) !of_property_read_bool(np, "fsl,err006687-workaround-present")) fep->quirks |= FEC_QUIRK_ERR006687; + fec_enet_of_parse_stop_mode(pdev); + if (of_get_property(np, "fsl,magic-packet", NULL)) fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET; @@ -3544,6 +3596,12 @@ fec_probe(struct platform_device *pdev) fep->irq[i] = irq; } + ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq); + if (!ret && irq < FEC_IRQ_NUM) + fep->wake_irq = fep->irq[irq]; + else + fep->wake_irq = fep->irq[0]; + init_completion(&fep->mdio_done); ret = fec_enet_mii_init(pdev); if (ret) @@ -3631,10 +3689,13 @@ static int __maybe_unused fec_suspend(struct device *dev) netif_device_detach(ndev); netif_tx_unlock_bh(ndev); fec_stop(ndev); - fec_enet_clk_enable(ndev, false); - if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) + if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { pinctrl_pm_select_sleep_state(&fep->pdev->dev); - pinctrl_pm_select_sleep_state(&fep->pdev->dev); + } else { + disable_irq(fep->wake_irq); + enable_irq_wake(fep->wake_irq); + } + fec_enet_clk_enable(ndev, false); } else if (fep->mii_bus_share && !ndev->phydev) { fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&fep->pdev->dev); @@ -3657,7 +3718,6 @@ static int __maybe_unused fec_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); - struct fec_platform_data *pdata = fep->pdev->dev.platform_data; int ret; int val; @@ -3674,9 +3734,11 @@ static int __maybe_unused fec_resume(struct device *dev) rtnl_unlock(); goto failed_clk; } + if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) { - if (pdata && pdata->sleep_mode_enable) - pdata->sleep_mode_enable(false); + disable_irq_wake(fep->wake_irq); + fec_enet_stop_mode(fep, false); + enable_irq(fep->wake_irq); val = readl(fep->hwp + FEC_ECNTRL); val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); writel(val, fep->hwp + FEC_ECNTRL); From 85fb383d5454c7dd009e1420511a37cdf227b2e6 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 22 Jul 2015 12:42:40 +0800 Subject: [PATCH 0016/3047] MLK-11274 net: fec: add mii bus up_failed flag to reflect the real status Add mii bus up_failed flag to reflect the real mii bus status. Signed-off-by: Fugang Duan Reported-and-tested-by: Zhang Sanshan (cherry picked from commit: ea348e597501d44841a28d8ee099361e89d63520) --- drivers/net/ethernet/freescale/fec.h | 1 + drivers/net/ethernet/freescale/fec_main.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index c9a16caf541b1d..2982850cfdc944 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -540,6 +540,7 @@ struct fec_enet_private { struct mii_bus *mii_bus; int mii_timeout; int mii_bus_share; + bool miibus_up_failed; uint phy_speed; phy_interface_t phy_interface; struct device_node *phy_node; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 48fd750f5ac44f..0f944941ed914f 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2933,12 +2933,14 @@ fec_enet_open(struct net_device *ndev) device_set_wakeup_enable(&ndev->dev, fep->wol_flag & FEC_WOL_FLAG_ENABLE); + fep->miibus_up_failed = false; return 0; err_enet_mii_probe: fec_enet_free_buffers(ndev); err_enet_alloc: + fep->miibus_up_failed = true; if (!fep->mii_bus_share) fec_enet_clk_enable(ndev, false); clk_enable: @@ -3696,7 +3698,7 @@ static int __maybe_unused fec_suspend(struct device *dev) enable_irq_wake(fep->wake_irq); } fec_enet_clk_enable(ndev, false); - } else if (fep->mii_bus_share && !ndev->phydev) { + } else if (fep->mii_bus_share && fep->miibus_up_failed && !ndev->phydev) { fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&fep->pdev->dev); } @@ -3754,6 +3756,8 @@ static int __maybe_unused fec_resume(struct device *dev) phy_start(ndev->phydev); } else if (fep->mii_bus_share && !ndev->phydev) { pinctrl_pm_select_default_state(&fep->pdev->dev); + fep->miibus_up_failed = true; + /* And then recovery mii bus */ fec_restore_mii_bus(ndev); } rtnl_unlock(); From aa65cca4372d082e86b0a7269bfe49c4731733df Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 14:53:21 +0800 Subject: [PATCH 0017/3047] MLK-10472-2 ARM: imx_v7_defconfig: enable max7322 in default config Enable max7322 extention gpio driver in config Signed-off-by: Fugang Duan Signed-off-by: Luwei Zhou (cherry picked from commit: 575b7e4c2f85b08fb09d6a639adb404718b9b644) --- arch/arm/configs/imx_v7_defconfig | 58 ++----------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index d3d9316571a9d0..18832e86d5e682 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -17,12 +17,9 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_MULTI_V6=y -CONFIG_GPIO_PCA953X=y CONFIG_ARCH_MXC=y # CONFIG_MACH_MX31ADS is not set # CONFIG_MACH_BUG is not set -CONFIG_MACH_IMX51_DT=y -CONFIG_MACH_EUKREA_CPUIMX51SD=y CONFIG_SOC_IMX50=y CONFIG_SOC_IMX53=y CONFIG_SOC_IMX6Q=y @@ -30,7 +27,6 @@ CONFIG_SOC_IMX6SL=y CONFIG_SOC_IMX6SX=y CONFIG_SOC_IMX7D=y CONFIG_SOC_VF610=y -# CONFIG_SWP_EMULATE is not set CONFIG_SMP=y CONFIG_HAVE_ARM_ARCH_TIMER=y CONFIG_VMSPLIT_2G=y @@ -40,8 +36,6 @@ CONFIG_HIGHMEM=y CONFIG_CMA=y CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y @@ -51,7 +45,6 @@ CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_BINFMT_MISC=m -CONFIG_PM_RUNTIME=y CONFIG_PM_DEBUG=y CONFIG_PM_TEST_SUSPEND=y CONFIG_NET=y @@ -80,7 +73,6 @@ CONFIG_BT_HIDP=y CONFIG_BT_HCIBTUSB=y CONFIG_BT_HCIBTSDIO=y CONFIG_BT_HCIUART=y -CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_BCSP=y CONFIG_BT_HCIUART_ATH3K=y CONFIG_BT_HCIBCM203X=y @@ -119,7 +111,6 @@ CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y @@ -156,7 +147,6 @@ CONFIG_BRCMFMAC=m CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_KEYBOARD_GPIO=y -CONFIG_KEYBOARD_SNVS_PWRKEY=y CONFIG_KEYBOARD_IMX=y CONFIG_MOUSE_PS2=m CONFIG_MOUSE_PS2_ELANTECH=y @@ -169,7 +159,6 @@ CONFIG_TOUCHSCREEN_TSC2007=y CONFIG_TOUCHSCREEN_STMPE=y CONFIG_INPUT_MISC=y CONFIG_INPUT_MMA8450=y -CONFIG_INPUT_ISL29023=y CONFIG_SERIO_SERPORT=m # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set @@ -177,7 +166,6 @@ CONFIG_SERIAL_IMX=y CONFIG_SERIAL_IMX_CONSOLE=y CONFIG_SERIAL_FSL_LPUART=y CONFIG_SERIAL_FSL_LPUART_CONSOLE=y -CONFIG_FSL_OTP=y # CONFIG_I2C_COMPAT is not set CONFIG_I2C_CHARDEV=y # CONFIG_I2C_HELPER_AUTO is not set @@ -187,27 +175,23 @@ CONFIG_I2C_IMX=y CONFIG_SPI=y CONFIG_SPI_IMX=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_MAX732X=y +CONFIG_GPIO_PCA953X=y CONFIG_POWER_SUPPLY=y -CONFIG_SABRESD_MAX8903=y -CONFIG_SENSORS_MAX17135=y -CONFIG_SENSORS_MAG3110=y CONFIG_THERMAL=y CONFIG_CPU_THERMAL=y CONFIG_IMX_THERMAL=y -CONFIG_DEVICE_THERMAL=y CONFIG_WATCHDOG=y CONFIG_IMX2_WDT=y CONFIG_MFD_DA9052_I2C=y CONFIG_MFD_MC13XXX_SPI=y CONFIG_MFD_MC13XXX_I2C=y -CONFIG_MFD_MAX17135=y CONFIG_MFD_SI476X_CORE=y CONFIG_MFD_STMPE=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_ANATOP=y CONFIG_REGULATOR_DA9052=y -CONFIG_REGULATOR_MAX17135=y CONFIG_REGULATOR_MC13783=y CONFIG_REGULATOR_MC13892=y CONFIG_REGULATOR_PFUZE100=y @@ -220,17 +204,6 @@ CONFIG_IR_GPIO_CIR=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_VIDEO_MXC_OUTPUT=y -CONFIG_VIDEO_MXC_CAPTURE=m -CONFIG_MXC_CAMERA_OV5640=m -CONFIG_MXC_CAMERA_OV5642=m -CONFIG_MXC_CAMERA_OV5640_MIPI=m -CONFIG_MXC_TVIN_ADV7180=m -CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m -CONFIG_VIDEO_MXC_IPU_OUTPUT=y -CONFIG_VIDEO_MXC_PXP_V4L2=y -CONFIG_VIDEO_MXC_CSI_CAMERA=m -CONFIG_MXC_VADC=m CONFIG_SOC_CAMERA=y CONFIG_VIDEO_MX3=y CONFIG_V4L_MEM2MEM_DRIVERS=y @@ -238,24 +211,12 @@ CONFIG_VIDEO_CODA=y CONFIG_RADIO_SI476X=y CONFIG_SOC_CAMERA_OV2640=y CONFIG_DRM=y -CONFIG_DRM_VIVANTE=y CONFIG_FB=y CONFIG_FB_MXS=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_L4F00242T03=y CONFIG_LCD_PLATFORM=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_PWM=y -CONFIG_FB_MXC_SYNC_PANEL=y -CONFIG_FB_MXC_LDB=y -CONFIG_FB_MXC_MIPI_DSI=y -CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y -CONFIG_FB_MXC_HDMI=y -CONFIG_FB_MXC_EINK_PANEL=y -CONFIG_FB_MXS_SII902X=y -CONFIG_FB_MXC_DCIC=m -CONFIG_HANNSTAR_CABC=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y @@ -265,14 +226,10 @@ CONFIG_SND_USB_AUDIO=m CONFIG_SND_SOC=y CONFIG_SND_IMX_SOC=y CONFIG_SND_SOC_EUKREA_TLV320=y -CONFIG_SND_SOC_IMX_CS42888=y CONFIG_SND_SOC_IMX_WM8962=y CONFIG_SND_SOC_IMX_SGTL5000=y -CONFIG_SND_SOC_IMX_MQS=y CONFIG_SND_SOC_IMX_SPDIF=y CONFIG_SND_SOC_IMX_MC13783=y -CONFIG_SND_SOC_IMX_HDMI=y -CONFIG_SND_SOC_IMX_SI476X=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y @@ -308,14 +265,9 @@ CONFIG_USB_GADGETFS=m CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y -CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y -CONFIG_MXC_IPU=y -CONFIG_MXC_GPU_VIV=y -CONFIG_MXC_MIPI_CSI2=y -CONFIG_MXC_MLB150=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y @@ -331,7 +283,6 @@ CONFIG_RTC_DRV_MC13XXX=y CONFIG_RTC_DRV_MXC=y CONFIG_RTC_DRV_SNVS=y CONFIG_DMADEVICES=y -CONFIG_MXC_PXP_V2=y CONFIG_IMX_SDMA=y CONFIG_MXS_DMA=y CONFIG_STAGING=y @@ -383,7 +334,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_SECURITYFS=y CONFIG_CRYPTO_USER=y CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_CTS=y CONFIG_CRYPTO_LRW=y @@ -404,10 +354,6 @@ CONFIG_CRYPTO_CAMELLIA=y CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_TWOFISH=y # CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DEV_FSL_CAAM=y -CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y -CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=y -CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y CONFIG_CRC_CCITT=m CONFIG_CRC_T10DIF=y CONFIG_CRC7=m From f27a5d0d617442e11e41239fe6cece0af1231275 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 19 May 2015 11:03:55 +0800 Subject: [PATCH 0018/3047] MLK-10920 ARM: imx_v7_defconfig: enable MICREL phy Enable CONFIG_MICREL_PHY for MICREL PHY since i.MX6ul boards install micrel ksz8081 phy. Signed-off-by: Fugang Duan (cherry picked from commit: 626d87758e1724ff92708da11e8af0081bb69ce9) --- arch/arm/configs/imx_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 18832e86d5e682..262bd0e9ce85f0 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -134,6 +134,7 @@ CONFIG_SMC91X=y CONFIG_SMC911X=y CONFIG_SMSC911X=y # CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_MICREL_PHY=y CONFIG_USB_PEGASUS=m CONFIG_USB_RTL8150=m CONFIG_USB_RTL8152=m From c9374a6cba0067d62a82f70c5e5b3c90a07a5764 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 15:40:00 +0800 Subject: [PATCH 0019/3047] MLK-10919 net: phy: micrel: add ksz8081 resume function Add ksz8081 resume function since the phy has some non-standard register init process that has some fixup. Signed-off-by: Fugang Duan (cherry picked from commit: 65c6e997b8e020b9e87d1af23c94c15c13e3d2e3) --- drivers/net/phy/micrel.c | 18 +++++++++++++++++- drivers/net/phy/phy_device.c | 3 ++- include/linux/phy.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2032a6de026bfd..52c24ac5d751d8 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -788,6 +788,22 @@ static int kszphy_probe(struct phy_device *phydev) return 0; } +static int ksz8081_resume(struct phy_device *phydev) +{ + int value; + + mutex_lock(&phydev->lock); + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); + + value = phy_scan_fixups(phydev); + if (value < 0) + return value; + mutex_unlock(&phydev->lock); + + return 0; +} + static struct phy_driver ksphy_driver[] = { { .phy_id = PHY_ID_KS8737, @@ -936,7 +952,7 @@ static struct phy_driver ksphy_driver[] = { .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, .suspend = kszphy_suspend, - .resume = kszphy_resume, + .resume = ksz8081_resume, }, { .phy_id = PHY_ID_KSZ8061, .name = "Micrel KSZ8061", diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index bf02f8e4648a4b..74690cd3c493c1 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -252,7 +252,7 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) } /* Runs any matching fixups for this phydev */ -static int phy_scan_fixups(struct phy_device *phydev) +int phy_scan_fixups(struct phy_device *phydev) { struct phy_fixup *fixup; @@ -272,6 +272,7 @@ static int phy_scan_fixups(struct phy_device *phydev) return 0; } +EXPORT_SYMBOL(phy_scan_fixups); static int phy_bus_match(struct device *dev, struct device_driver *drv) { diff --git a/include/linux/phy.h b/include/linux/phy.h index 867110c9d70793..cc374eb47c26da 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -833,6 +833,7 @@ void phy_print_status(struct phy_device *phydev); void phy_device_free(struct phy_device *phydev); int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); +int phy_scan_fixups(struct phy_device *phydev); int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, int (*run)(struct phy_device *)); int phy_register_fixup_for_id(const char *bus_id, From 5b1b1cf3f898c5612f78beeb66f5ff9ecfe2f281 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 14:38:38 +0800 Subject: [PATCH 0020/3047] MLK-11288 ARM: dts: imx7d-sdb: add fec1, fec2 support Add fec1, fec2 support for i.MX7d-sdb board. Signed-off-by: Fugang Duan --- arch/arm/boot/dts/imx7d-sdb.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 2f33c463cbce4f..8bf6316f1520ca 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -153,10 +153,12 @@ #size-cells = <0>; ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; }; ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; }; }; From 89e4aa182faa25d7c22390e9c50460b328e2112a Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 16:28:48 +0800 Subject: [PATCH 0021/3047] MLK-10369 ARM: dts: Add i2c bus support for i.MX7d-sdb board - Add i2c1,2,3,4 bus support for i.MX7d-sdb board (i2c4 bus need to rework: swap R485 and R33). - Add i2c device PMIC support. Signed-off-by: Fugang Duan (cherry picked from commit: 45acb911f7192fcc574f1e0faaf19513b9879046) --- arch/arm/boot/dts/imx7d-sdb.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 8bf6316f1520ca..340f81656268ea 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -178,6 +178,7 @@ }; &i2c1 { + clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; @@ -274,18 +275,21 @@ }; &i2c2 { + clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; }; &i2c3 { + clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3>; status = "okay"; }; &i2c4 { + clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c4>; status = "okay"; From 53910ae51a55601006ff03fed9f0c1063f3dcdca Mon Sep 17 00:00:00 2001 From: Luwei Zhou Date: Tue, 16 Sep 2014 13:05:41 +0800 Subject: [PATCH 0022/3047] MLK-10833-1 hwmon: mag3110: Add mag3110 driver support on i.MX6Q/DL/SX platform. Add mag3110 driver support for i.MX6Q/DL/SX platform. The code derives from 3.10.y branch. Signed-off-by: Luwei Zhou Signed-off-by: Fugang Duan (cherry picked from commit: dd027baab7652c62d26f1749f334099e4dbe61c9) --- drivers/hwmon/Kconfig | 9 + drivers/hwmon/Makefile | 1 + drivers/hwmon/mag3110.c | 654 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 664 insertions(+) create mode 100644 drivers/hwmon/mag3110.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 45cef3d2c75c61..734e719af89291 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1857,4 +1857,13 @@ config SENSORS_ATK0110 endif # ACPI +config SENSORS_MAG3110 + tristate "Freescale MAG3110 e-compass sensor" + depends on I2C && SYSFS + help + If you say yes here you get support for the Freescale MAG3110 + e-compass sensor. + This driver can also be built as a module. If so, the module + will be called mag3110. + endif # HWMON diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index aecf4ba1746019..db0decbaea73f9 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -166,6 +166,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o +obj-$(CONFIG_SENSORS_MAG3110) += mag3110.o obj-$(CONFIG_PMBUS) += pmbus/ diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c new file mode 100644 index 00000000000000..3278bae36a2a2b --- /dev/null +++ b/drivers/hwmon/mag3110.c @@ -0,0 +1,654 @@ +/* + * + * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAG3110_DRV_NAME "mag3110" +#define MAG3110_ID (0xC4) +#define MAG3110_XYZ_DATA_LEN (6) +#define MAG3110_STATUS_ZYXDR (0x08) +#define MAG3110_IRQ_USED (1) +#define MAG3110_AC_MASK (0x01) +#define MAG3110_AC_OFFSET (0) +#define MAG3110_DR_MODE_MASK (0x7 << 5) +#define MAG3110_DR_MODE_OFFSET (5) + +#define POLL_INTERVAL_MAX (500) +#define POLL_INTERVAL (100) +#define INT_TIMEOUT (1000) +#define DEFAULT_POSITION (2) + +/* register enum for mag3110 registers */ +enum { + MAG3110_DR_STATUS = 0x00, + MAG3110_OUT_X_MSB, + MAG3110_OUT_X_LSB, + MAG3110_OUT_Y_MSB, + MAG3110_OUT_Y_LSB, + MAG3110_OUT_Z_MSB, + MAG3110_OUT_Z_LSB, + MAG3110_WHO_AM_I, + + MAG3110_OFF_X_MSB, + MAG3110_OFF_X_LSB, + MAG3110_OFF_Y_MSB, + MAG3110_OFF_Y_LSB, + MAG3110_OFF_Z_MSB, + MAG3110_OFF_Z_LSB, + + MAG3110_DIE_TEMP, + + MAG3110_CTRL_REG1 = 0x10, + MAG3110_CTRL_REG2, +}; + +enum { + MAG_STANDBY, + MAG_ACTIVED +}; + +struct mag3110_data { + struct i2c_client *client; + struct input_polled_dev *poll_dev; + struct device *hwmon_dev; + wait_queue_head_t waitq; + bool data_ready; + u8 ctl_reg1; + int active; + int position; +}; + +static short MAGHAL[8][3][3] = { + { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, + { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }, + { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} }, + { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} }, + + { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} }, + { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} }, + { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, + { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} }, +}; + +static struct mag3110_data *mag3110_pdata; +static DEFINE_MUTEX(mag3110_lock); + +/* + * This function do one mag3110 register read. + */ +static int mag3110_adjust_position(short *x, short *y, short *z) +{ + short rawdata[3], data[3]; + int i, j; + int position = mag3110_pdata->position; + if (position < 0 || position > 7) + position = 0; + rawdata[0] = *x; + rawdata[1] = *y; + rawdata[2] = *z; + for (i = 0; i < 3; i++) { + data[i] = 0; + for (j = 0; j < 3; j++) + data[i] += rawdata[j] * MAGHAL[position][i][j]; + } + *x = data[0]; + *y = data[1]; + *z = data[2]; + return 0; +} + +static int mag3110_read_reg(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +/* + * This function do one mag3110 register write. + */ +static int mag3110_write_reg(struct i2c_client *client, u8 reg, char value) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, reg, value); + if (ret < 0) + dev_err(&client->dev, "i2c write failed\n"); + return ret; +} + +/* + * This function do multiple mag3110 registers read. + */ +static int mag3110_read_block_data(struct i2c_client *client, u8 reg, + int count, u8 *addr) +{ + if (i2c_smbus_read_i2c_block_data(client, reg, count, addr) < count) { + dev_err(&client->dev, "i2c block read failed\n"); + return -1; + } + + return count; +} + +/* + * Initialization function + */ +static int mag3110_init_client(struct i2c_client *client) +{ + int val, ret; + + /* enable automatic resets */ + val = 0x80; + ret = mag3110_write_reg(client, MAG3110_CTRL_REG2, val); + + /* set default data rate to 10HZ */ + val = mag3110_read_reg(client, MAG3110_CTRL_REG1); + val |= (0x0 << MAG3110_DR_MODE_OFFSET); + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, val); + + return ret; +} + +/* + * read sensor data from mag3110 + */ +static int mag3110_read_data(short *x, short *y, short *z) +{ + struct mag3110_data *data; + u8 tmp_data[MAG3110_XYZ_DATA_LEN]; +#if !MAG3110_IRQ_USED + int retry = 3; + int result; +#endif + if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY) + return -EINVAL; + + data = mag3110_pdata; +#if MAG3110_IRQ_USED + if (!wait_event_interruptible_timeout + (data->waitq, data->data_ready != 0, + msecs_to_jiffies(INT_TIMEOUT))) { + dev_dbg(&data->client->dev, "interrupt not received\n"); + return -ETIME; + } +#else + do { + msleep(1); + result = i2c_smbus_read_byte_data(data->client, + MAG3110_DR_STATUS); + retry--; + } while (!(result & MAG3110_STATUS_ZYXDR) && retry > 0); + /* Clear data_ready flag after data is read out */ + if (retry == 0) + return -EINVAL; +#endif + + data->data_ready = 0; + + while (i2c_smbus_read_byte_data(data->client, MAG3110_DR_STATUS)) { + if (mag3110_read_block_data(data->client, + MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN, + tmp_data) < 0) + return -1; + } + + *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; + *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; + *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; + + return 0; +} + +static void report_abs(void) +{ + struct input_dev *idev; + short x, y, z; + + mutex_lock(&mag3110_lock); + if (mag3110_read_data(&x, &y, &z) != 0) + goto out; + mag3110_adjust_position(&x, &y, &z); + idev = mag3110_pdata->poll_dev->input; + input_report_abs(idev, ABS_X, x); + input_report_abs(idev, ABS_Y, y); + input_report_abs(idev, ABS_Z, z); + input_sync(idev); +out: + mutex_unlock(&mag3110_lock); +} + +static void mag3110_dev_poll(struct input_polled_dev *dev) +{ + report_abs(); +} + +#if MAG3110_IRQ_USED +static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) +{ + int result; + u8 tmp_data[MAG3110_XYZ_DATA_LEN]; + result = i2c_smbus_read_byte_data(mag3110_pdata->client, + MAG3110_DR_STATUS); + if (!(result & MAG3110_STATUS_ZYXDR)) + return IRQ_NONE; + + mag3110_pdata->data_ready = 1; + + if (mag3110_pdata->active == MAG_STANDBY) + /* + * Since the mode will be changed, sometimes irq will + * be handled in StandBy mode because of interrupt latency. + * So just clear the interrutp flag via reading block data. + */ + mag3110_read_block_data(mag3110_pdata->client, + MAG3110_OUT_X_MSB, + MAG3110_XYZ_DATA_LEN, tmp_data); + else + wake_up_interruptible(&mag3110_pdata->waitq); + + return IRQ_HANDLED; +} +#endif + +static ssize_t mag3110_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client; + int val; + mutex_lock(&mag3110_lock); + client = mag3110_pdata->client; + val = mag3110_read_reg(client, MAG3110_CTRL_REG1) & MAG3110_AC_MASK; + + mutex_unlock(&mag3110_lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t mag3110_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client; + int reg, ret; + long enable; + u8 tmp_data[MAG3110_XYZ_DATA_LEN]; + + ret = kstrtol(buf, 10, &enable); + if (ret) { + dev_err(dev, "string to long error\n"); + return ret; + } + + mutex_lock(&mag3110_lock); + client = mag3110_pdata->client; + + reg = mag3110_read_reg(client, MAG3110_CTRL_REG1); + if (enable && mag3110_pdata->active == MAG_STANDBY) { + reg |= MAG3110_AC_MASK; + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); + if (!ret) + mag3110_pdata->active = MAG_ACTIVED; + } else if (!enable && mag3110_pdata->active == MAG_ACTIVED) { + reg &= ~MAG3110_AC_MASK; + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); + if (!ret) + mag3110_pdata->active = MAG_STANDBY; + } + + /* Read out MSB data to clear interrupt flag */ + msleep(100); + mag3110_read_block_data(mag3110_pdata->client, MAG3110_OUT_X_MSB, + MAG3110_XYZ_DATA_LEN, tmp_data); + mutex_unlock(&mag3110_lock); + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, + mag3110_enable_show, mag3110_enable_store); + +static ssize_t mag3110_dr_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client; + int val; + + client = mag3110_pdata->client; + val = (mag3110_read_reg(client, MAG3110_CTRL_REG1) + & MAG3110_DR_MODE_MASK) >> MAG3110_DR_MODE_OFFSET; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t mag3110_dr_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client; + int reg, ret; + unsigned long val; + + /* This must be done when mag3110 is disabled */ + if ((kstrtoul(buf, 10, &val) < 0) || (val > 7)) + return -EINVAL; + + client = mag3110_pdata->client; + reg = mag3110_read_reg(client, MAG3110_CTRL_REG1) & + ~MAG3110_DR_MODE_MASK; + reg |= (val << MAG3110_DR_MODE_OFFSET); + /* MAG3110_CTRL_REG1 bit 5-7: data rate mode */ + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(dr_mode, S_IWUSR | S_IRUGO, + mag3110_dr_mode_show, mag3110_dr_mode_store); + +static ssize_t mag3110_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int val; + mutex_lock(&mag3110_lock); + val = mag3110_pdata->position; + mutex_unlock(&mag3110_lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t mag3110_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + long position; + int ret; + ret = kstrtol(buf, 10, &position); + if (ret) { + dev_err(dev, "string to long error\n"); + return ret; + } + + mutex_lock(&mag3110_lock); + mag3110_pdata->position = (int)position; + mutex_unlock(&mag3110_lock); + return count; +} + +static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, + mag3110_position_show, mag3110_position_store); + +static struct attribute *mag3110_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_dr_mode.attr, + &dev_attr_position.attr, + NULL +}; + +static const struct attribute_group mag3110_attr_group = { + .attrs = mag3110_attributes, +}; + +static int mag3110_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter; + struct input_dev *idev; + struct mag3110_data *data; + int ret = 0; + struct regulator *vdd, *vdd_io; + u32 pos = 0; + struct device_node *of_node = client->dev.of_node; +#if MAG3110_IRQ_USED + struct irq_data *irq_data = irq_get_irq_data(client->irq); + u32 irq_flag; + bool shared_irq = of_property_read_bool(of_node, "shared-interrupt"); +#endif + vdd = NULL; + vdd_io = NULL; + + vdd = devm_regulator_get(&client->dev, "vdd"); + if (!IS_ERR(vdd)) { + ret = regulator_enable(vdd); + if (ret) { + dev_err(&client->dev, "vdd set voltage error\n"); + return ret; + } + } + + vdd_io = devm_regulator_get(&client->dev, "vddio"); + if (!IS_ERR(vdd_io)) { + ret = regulator_enable(vdd_io); + if (ret) { + dev_err(&client->dev, "vddio set voltage error\n"); + return ret; + } + } + + adapter = to_i2c_adapter(client->dev.parent); + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -EIO; + + dev_info(&client->dev, "check mag3110 chip ID\n"); + ret = mag3110_read_reg(client, MAG3110_WHO_AM_I); + + if (MAG3110_ID != ret) { + dev_err(&client->dev, + "read chip ID 0x%x is not equal to 0x%x!\n", ret, + MAG3110_ID); + return -EINVAL; + } + data = kzalloc(sizeof(struct mag3110_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->client = client; + i2c_set_clientdata(client, data); + /* Init queue */ + init_waitqueue_head(&data->waitq); + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + dev_err(&client->dev, "hwmon register failed!\n"); + ret = PTR_ERR(data->hwmon_dev); + goto error_rm_dev_sysfs; + } + + /*input poll device register */ + data->poll_dev = input_allocate_polled_device(); + if (!data->poll_dev) { + dev_err(&client->dev, "alloc poll device failed!\n"); + ret = -ENOMEM; + goto error_rm_hwmon_dev; + } + data->poll_dev->poll = mag3110_dev_poll; + data->poll_dev->poll_interval = POLL_INTERVAL; + data->poll_dev->poll_interval_max = POLL_INTERVAL_MAX; + idev = data->poll_dev->input; + idev->name = MAG3110_DRV_NAME; + idev->id.bustype = BUS_I2C; + idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(idev, ABS_X, -15000, 15000, 0, 0); + input_set_abs_params(idev, ABS_Y, -15000, 15000, 0, 0); + input_set_abs_params(idev, ABS_Z, -15000, 15000, 0, 0); + ret = input_register_polled_device(data->poll_dev); + if (ret) { + dev_err(&client->dev, "register poll device failed!\n"); + goto error_free_poll_dev; + } + + /*create device group in sysfs as user interface */ + ret = sysfs_create_group(&idev->dev.kobj, &mag3110_attr_group); + if (ret) { + dev_err(&client->dev, "create device file failed!\n"); + ret = -EINVAL; + goto error_rm_poll_dev; + } + +#if MAG3110_IRQ_USED + irq_flag = irqd_get_trigger_type(irq_data); + irq_flag |= IRQF_ONESHOT; + if (shared_irq) + irq_flag |= IRQF_SHARED; + ret = request_threaded_irq(client->irq, NULL, mag3110_irq_handler, + irq_flag, client->dev.driver->name, idev); + if (ret < 0) { + dev_err(&client->dev, "failed to register irq %d!\n", + client->irq); + goto error_rm_dev_sysfs; + } +#endif + /* Initialize mag3110 chip */ + mag3110_init_client(client); + mag3110_pdata = data; + mag3110_pdata->active = MAG_STANDBY; + ret = of_property_read_u32(of_node, "position", &pos); + if (ret) + pos = DEFAULT_POSITION; + mag3110_pdata->position = (int)pos; + dev_info(&client->dev, "mag3110 is probed\n"); + return 0; +error_rm_dev_sysfs: + sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); +error_rm_poll_dev: + input_unregister_polled_device(data->poll_dev); +error_free_poll_dev: + input_free_polled_device(data->poll_dev); +error_rm_hwmon_dev: + hwmon_device_unregister(data->hwmon_dev); + + kfree(data); + mag3110_pdata = NULL; + + return ret; +} + +static int mag3110_remove(struct i2c_client *client) +{ + struct mag3110_data *data; + int ret; + + data = i2c_get_clientdata(client); + + data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, + data->ctl_reg1 & ~MAG3110_AC_MASK); + + free_irq(client->irq, data); + input_unregister_polled_device(data->poll_dev); + input_free_polled_device(data->poll_dev); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); + kfree(data); + mag3110_pdata = NULL; + + return ret; +} + +#ifdef CONFIG_PM +static int mag3110_suspend(struct device *dev) +{ + int ret = 0; + struct i2c_client *client = to_i2c_client(dev); + struct mag3110_data *data = i2c_get_clientdata(client); + + if (data->active == MAG_ACTIVED) { + data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, + data->ctl_reg1 & ~MAG3110_AC_MASK); + } + return ret; +} + +static int mag3110_resume(struct device *dev) +{ + int ret = 0; + struct i2c_client *client = to_i2c_client(dev); + struct mag3110_data *data = i2c_get_clientdata(client); + u8 tmp_data[MAG3110_XYZ_DATA_LEN]; + + if (data->active == MAG_ACTIVED) { + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, + data->ctl_reg1); + + if (data->ctl_reg1 & MAG3110_AC_MASK) { + /* Read out MSB data to clear interrupt + flag automatically */ + mag3110_read_block_data(client, MAG3110_OUT_X_MSB, + MAG3110_XYZ_DATA_LEN, tmp_data); + } + } + return ret; +} + +static const struct dev_pm_ops mag3110_dev_pm_ops = { + .suspend = mag3110_suspend, + .resume = mag3110_resume, +}; +#define MAG3110_DEV_PM_OPS (&mag3110_dev_pm_ops) + +#else +#define MAG3110_DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + +static const struct i2c_device_id mag3110_id[] = { + {MAG3110_DRV_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mag3110_id); +static struct i2c_driver mag3110_driver = { + .driver = { + .name = MAG3110_DRV_NAME, + .owner = THIS_MODULE, + .pm = MAG3110_DEV_PM_OPS, + }, + .probe = mag3110_probe, + .remove = mag3110_remove, + .id_table = mag3110_id, +}; + +static int __init mag3110_init(void) +{ + return i2c_add_driver(&mag3110_driver); +} + +static void __exit mag3110_exit(void) +{ + i2c_del_driver(&mag3110_driver); +} + +module_init(mag3110_init); +module_exit(mag3110_exit); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Freescale mag3110 3-axis magnetometer driver"); +MODULE_LICENSE("GPL"); From 1d7c8b6fd20a063bdac1e2af0bf7560a9105dd34 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 6 May 2015 19:37:44 +0800 Subject: [PATCH 0023/3047] MLK-10833-2 hwmon: mag3110: use global variable instead of macro define Use global variable instead of macro "MAG3110_IRQ_USED" that is more flexible. Signed-off-by: Fugang Duan --- drivers/hwmon/mag3110.c | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c index 3278bae36a2a2b..c8ddc8287d38a8 100644 --- a/drivers/hwmon/mag3110.c +++ b/drivers/hwmon/mag3110.c @@ -37,7 +37,6 @@ #define MAG3110_ID (0xC4) #define MAG3110_XYZ_DATA_LEN (6) #define MAG3110_STATUS_ZYXDR (0x08) -#define MAG3110_IRQ_USED (1) #define MAG3110_AC_MASK (0x01) #define MAG3110_AC_OFFSET (0) #define MAG3110_DR_MODE_MASK (0x7 << 5) @@ -86,6 +85,7 @@ struct mag3110_data { u8 ctl_reg1; int active; int position; + int use_irq; }; static short MAGHAL[8][3][3] = { @@ -185,22 +185,20 @@ static int mag3110_read_data(short *x, short *y, short *z) { struct mag3110_data *data; u8 tmp_data[MAG3110_XYZ_DATA_LEN]; -#if !MAG3110_IRQ_USED int retry = 3; int result; -#endif + if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY) return -EINVAL; data = mag3110_pdata; -#if MAG3110_IRQ_USED - if (!wait_event_interruptible_timeout + if (data->use_irq && !wait_event_interruptible_timeout (data->waitq, data->data_ready != 0, msecs_to_jiffies(INT_TIMEOUT))) { dev_dbg(&data->client->dev, "interrupt not received\n"); return -ETIME; } -#else + do { msleep(1); result = i2c_smbus_read_byte_data(data->client, @@ -210,7 +208,6 @@ static int mag3110_read_data(short *x, short *y, short *z) /* Clear data_ready flag after data is read out */ if (retry == 0) return -EINVAL; -#endif data->data_ready = 0; @@ -251,7 +248,6 @@ static void mag3110_dev_poll(struct input_polled_dev *dev) report_abs(); } -#if MAG3110_IRQ_USED static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) { int result; @@ -277,7 +273,6 @@ static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -#endif static ssize_t mag3110_enable_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -420,17 +415,16 @@ static int mag3110_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter; - struct input_dev *idev; + struct input_dev *idev = NULL; struct mag3110_data *data; int ret = 0; struct regulator *vdd, *vdd_io; u32 pos = 0; struct device_node *of_node = client->dev.of_node; -#if MAG3110_IRQ_USED - struct irq_data *irq_data = irq_get_irq_data(client->irq); u32 irq_flag; + struct irq_data *irq_data = NULL; bool shared_irq = of_property_read_bool(of_node, "shared-interrupt"); -#endif + vdd = NULL; vdd_io = NULL; @@ -483,6 +477,11 @@ static int mag3110_probe(struct i2c_client *client, goto error_rm_dev_sysfs; } + if (client->irq > 0) { + data->use_irq = 1; + irq_data = irq_get_irq_data(client->irq); + } + /*input poll device register */ data->poll_dev = input_allocate_polled_device(); if (!data->poll_dev) { @@ -514,19 +513,20 @@ static int mag3110_probe(struct i2c_client *client, goto error_rm_poll_dev; } -#if MAG3110_IRQ_USED - irq_flag = irqd_get_trigger_type(irq_data); - irq_flag |= IRQF_ONESHOT; - if (shared_irq) - irq_flag |= IRQF_SHARED; - ret = request_threaded_irq(client->irq, NULL, mag3110_irq_handler, - irq_flag, client->dev.driver->name, idev); - if (ret < 0) { - dev_err(&client->dev, "failed to register irq %d!\n", - client->irq); - goto error_rm_dev_sysfs; + if (data->use_irq) { + irq_flag = irqd_get_trigger_type(irq_data); + irq_flag |= IRQF_ONESHOT; + if (shared_irq) + irq_flag |= IRQF_SHARED; + ret = request_threaded_irq(client->irq, NULL, mag3110_irq_handler, + irq_flag, client->dev.driver->name, idev); + if (ret < 0) { + dev_err(&client->dev, "failed to register irq %d!\n", + client->irq); + goto error_rm_dev_sysfs; + } } -#endif + /* Initialize mag3110 chip */ mag3110_init_client(client); mag3110_pdata = data; From 16d1d2d84687e9742856aef628c42f3b6e148e8b Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 16:41:32 +0800 Subject: [PATCH 0024/3047] MLK-10833-3 imx_v7_defconfig: enable mag3110 by default Enable mag3110 driver in default config. Signed-off-by: Luwei Zhou Signed-off-by: Fugang Duan (cherry picked from commit: ac43097186e94d5ecfdbc3c6a514aa20e5a7f8ca) --- arch/arm/configs/imx_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 262bd0e9ce85f0..bc9e5ed2ad6732 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -179,6 +179,7 @@ CONFIG_GPIO_SYSFS=y CONFIG_GPIO_MAX732X=y CONFIG_GPIO_PCA953X=y CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_MAG3110=y CONFIG_THERMAL=y CONFIG_CPU_THERMAL=y CONFIG_IMX_THERMAL=y From 4b56e261f31f41ea7d6fa68682501867ea7d0568 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 5 May 2015 17:08:34 +0800 Subject: [PATCH 0025/3047] MLK-10835-1 misc: fxas2100x: add Freescale FXAS2100X gyroscope sensor Add Freescale FXAS2100X gyroscope sensor Signed-off-by: Fugang Duan (cherry picked from commit: 34a99f00d4886f95a8cf8cd4acbf37a82c67e46c) --- drivers/misc/Kconfig | 10 + drivers/misc/Makefile | 1 + drivers/misc/fxas2100x.c | 618 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 629 insertions(+) create mode 100644 drivers/misc/fxas2100x.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 64971baf11faeb..fcd4d7c4a5a486 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -335,6 +335,16 @@ config ISL29020 This driver can also be built as a module. If so, the module will be called isl29020. +config SENSORS_FXAS2100X + tristate "Freescale FXAS2100X gyroscope sensor" + depends on I2C && SYSFS + help + If you say yes here you get support for the Freescale FXAS2100X + gyroscope sensor. + + This driver can also be built as a module. If so, the module + will be called fxas2100x. + config SENSORS_TSL2550 tristate "Taos TSL2550 ambient light sensor" depends on I2C && SYSFS diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 31983366090a78..88cc6af7c8df5a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o +obj-$(CONFIG_SENSORS_FXAS2100X) += fxas2100x.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o obj-$(CONFIG_SGI_IOC4) += ioc4.o diff --git a/drivers/misc/fxas2100x.c b/drivers/misc/fxas2100x.c new file mode 100644 index 00000000000000..3ac718067a7540 --- /dev/null +++ b/drivers/misc/fxas2100x.c @@ -0,0 +1,618 @@ +/* + * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SENSOR_IOCTL_BASE 'S' +#define SENSOR_GET_MODEL_NAME _IOR(SENSOR_IOCTL_BASE, 0, char *) +#define SENSOR_GET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 2, int) +#define SENSOR_SET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 3, int) +#define SENSOR_GET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 4, int) +#define SENSOR_SET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 5, int) +#define SENSOR_GET_RAW_DATA _IOR(SENSOR_IOCTL_BASE, 6, short[3]) + +#define FXAS2100X_I2C_ADDR 0x20 +#define FXAS21000_CHIP_ID 0xD1 +#define FXAS21002_CHID_ID_1 0xD6 +#define FXAS21002_CHID_ID_2 0xD7 + +#define FXAS2100X_POSITION_DEFAULT 2 +#define FXAS2100X_DELAY_DEFAULT 200 + +#define FXAS2100X_STATUS_ZYXDR 0x08 +#define FXAS2100X_BUF_SIZE 6 + +#define FXAS2100X_POLL_INTERVAL 400 +#define FXAS2100X_POLL_MAX 800 +#define FXAS2100X_POLL_MIN 200 +#define ABSMIN_GYRO_VAL -32768 +#define ABSMAX_GYRO_VAL 32768 + +#define FXAS2100X_DRIVER "fxas2100x" + +/* register enum for fxas2100x registers */ +enum { + FXAS2100X_STATUS = 0x00, + FXAS2100X_OUT_X_MSB, + FXAS2100X_OUT_X_LSB, + FXAS2100X_OUT_Y_MSB, + FXAS2100X_OUT_Y_LSB, + FXAS2100X_OUT_Z_MSB, + FXAS2100X_OUT_Z_LSB, + FXAS2100X_DR_STATUS, + FXAS2100X_F_STATUS, + FXAS2100X_F_SETUP, + FXAS2100X_F_EVENT, + FXAS2100X_INT_SRC_FLAG, + FXAS2100X_WHO_AM_I, + FXAS2100X_CTRL_REG0, + FXAS2100X_RT_CFG, + FXAS2100X_RT_SRC, + FXAS2100X_RT_THS, + FXAS2100X_RT_COUNT, + FXAS2100X_TEMP, + FXAS2100X_CTRL_REG1, + FXAS2100X_CTRL_REG2, + FXAS2100X_CTRL_REG3, /* fxos21002 special */ + FXAS2100X_REG_END, +}; + +enum { + STANDBY = 0, + ACTIVED, +}; + +struct fxas2100x_data_axis { + short x; + short y; + short z; +}; + +struct fxas2100x_data { + struct i2c_client *client; + struct input_polled_dev *input_polled; + atomic_t active; + atomic_t active_poll; + atomic_t delay; + atomic_t position; + u8 chip_id; +}; + +static struct fxas2100x_data *g_fxas2100x_data; + +static int fxas2100x_position_setting[8][3][3] = { + { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} }, + { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} }, + { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, + { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }, + { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, + { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} }, + { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} }, + { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} }, +}; + +static int fxas2100x_data_convert(struct fxas2100x_data *pdata, + struct fxas2100x_data_axis *axis_data) +{ + short rawdata[3], data[3]; + int i, j; + int position = atomic_read(&pdata->position); + + if (position < 0 || position > 7) + position = 0; + rawdata[0] = axis_data->x; + rawdata[1] = axis_data->y; + rawdata[2] = axis_data->z; + for (i = 0; i < 3; i++) { + data[i] = 0; + for (j = 0; j < 3; j++) + data[i] += rawdata[j] * fxas2100x_position_setting[position][i][j]; + } + axis_data->x = data[0]; + axis_data->y = data[1]; + axis_data->z = data[2]; + return 0; +} + +static int fxas2100x_device_init(struct i2c_client *client) +{ + int result; + u8 val; + struct fxas2100x_data *pdata = i2c_get_clientdata(client); + if (pdata->chip_id == FXAS21000_CHIP_ID) + val = (0x01 << 2); /* fxas21000 dr 200HZ */ + else + val = (0x02 << 2); /* fxas21002 dr 200HZ */ + result = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val); + if (result < 0) + goto out; + atomic_set(&pdata->active, STANDBY); + return 0; +out: + dev_err(&client->dev, "error when init fxas2100x:(%d)", result); + return result; +} + +static int fxas2100x_change_mode(struct i2c_client *client, int mode) +{ + u8 val; + int ret; + if (mode == ACTIVED) { + val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1); + val &= ~0x03; + val |= 0x02; + /* set bit 1 */ + ret = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val); + } else { + val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1); + val &= (~0x03); + /* clear bit 0,1 */ + ret = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val); + } + return ret; +} + +static int fxas2100x_set_delay(struct i2c_client *client, int delay) +{ + return 0; +} + +static int fxas2100x_device_stop(struct i2c_client *client) +{ + u8 val; + val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1); + val &= ~0x03; + i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val); + return 0; +} + +static int fxas2100x_read_data(struct fxas2100x_data *pdata, + struct fxas2100x_data_axis *data) +{ + struct i2c_client * client = pdata->client; + int x, y, z; + u8 tmp_data[FXAS2100X_BUF_SIZE]; + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, FXAS2100X_OUT_X_MSB, + FXAS2100X_BUF_SIZE, tmp_data); + if (ret < FXAS2100X_BUF_SIZE) { + dev_err(&client->dev, "i2c block read failed\n"); + return -EIO; + } + data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; + data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; + data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; + if (pdata->chip_id == FXAS21000_CHIP_ID) { + x = data->x; + y = data->y; + z = data->z; + x = x * 4 / 5; + y = y * 4 / 5; + z = z * 4 / 5; + data->x = x; + data->y = y; + data->z = z; + } + + return 0; +} + +/* fxas2100x miscdevice */ +static long fxas2100x_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct fxas2100x_data *pdata = file->private_data; + void __user *argp = (void __user *)arg; + struct fxas2100x_data_axis data; + long ret = 0; + short sdata[3]; + int enable; + int delay; + + if (!pdata) { + printk(KERN_ERR "FXAS2100X struct datt point is NULL."); + return -EFAULT; + } + + switch (cmd) { + case SENSOR_GET_MODEL_NAME: + if (copy_to_user(argp, "FXAS2100X GYRO", strlen("FXAS2100X GYRO") + 1)) { + printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_GET_POWER_STATUS: + enable = atomic_read(&pdata->active); + if (copy_to_user(argp, &enable, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_SET_POWER_STATUS: + if (copy_from_user(&enable, argp, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + if (pdata->client) { + ret = fxas2100x_change_mode(pdata->client, enable ? ACTIVED : STANDBY); + if (!ret) + atomic_set(&pdata->active, enable); + } + break; + case SENSOR_GET_DELAY_TIME: + delay = atomic_read(&pdata->delay); + if (copy_to_user(argp, &delay, sizeof(delay))) { + printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed."); + return -EFAULT; + } + break; + case SENSOR_SET_DELAY_TIME: + if (copy_from_user(&delay, argp, sizeof(int))) { + printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed."); + ret = -EFAULT; + } + if (pdata->client && delay > 0 && delay <= 500) { + ret = fxas2100x_set_delay(pdata->client, delay); + if (!ret) + atomic_set(&pdata->delay, delay); + } + break; + case SENSOR_GET_RAW_DATA: + ret = fxas2100x_read_data(pdata, &data); + if (!ret) { + fxas2100x_data_convert(pdata, &data); + sdata[0] = data.x; + sdata[1] = data.y; + sdata[2] = data.z; + if (copy_to_user(argp, sdata, sizeof(sdata))) { + printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed."); + ret = -EFAULT; + } + } + break; + default: + ret = -1; + } + + return ret; +} + +static int fxas2100x_open(struct inode *inode, struct file *file) +{ + file->private_data = g_fxas2100x_data; + return nonseekable_open(inode, file); +} + +static int fxas2100x_release(struct inode *inode, struct file *file) +{ + /* note: releasing the wdt in NOWAYOUT-mode does not stop it */ + return 0; +} + +static const struct file_operations fxas2100x_fops = { + .owner = THIS_MODULE, + .open = fxas2100x_open, + .release = fxas2100x_release, + .unlocked_ioctl = fxas2100x_ioctl, +}; + +static struct miscdevice fxas2100x_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "FreescaleGyroscope", + .fops = &fxas2100x_fops, +}; + +static ssize_t fxas2100x_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + int enable = 0; + enable = atomic_read(&pdata->active); + return sprintf(buf, "%d\n", enable); +} + +static ssize_t fxas2100x_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + struct i2c_client *client = pdata->client; + int ret; + unsigned long enable; + + if (kstrtoul(buf, 10, &enable) < 0) + return -EINVAL; + + enable = (enable > 0) ? 1 : 0; + ret = fxas2100x_change_mode(client, (enable > 0 ? ACTIVED : STANDBY)); + if (!ret) { + atomic_set(&pdata->active, enable); + atomic_set(&pdata->active_poll, enable); + dev_err(dev, "mma enable setting active \n"); + } + return count; +} + +static ssize_t fxas2100x_poll_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + int delay = 0; + + delay = atomic_read(&pdata->delay); + return sprintf(buf, "%d\n", delay); +} + +static ssize_t fxas2100x_poll_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + struct i2c_client *client = pdata->client; + int ret; + int delay; + + delay = simple_strtoul(buf, NULL, 10); + ret = fxas2100x_set_delay(client, delay); + if (!ret) + atomic_set(&pdata->delay, delay); + return count; +} + +static ssize_t fxas2100x_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + int position = 0; + + position = atomic_read(&pdata->position); + return sprintf(buf, "%d\n", position); +} + +static ssize_t fxas2100x_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + int position; + + position = simple_strtoul(buf, NULL, 10); + atomic_set(&pdata->position, position); + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxas2100x_enable_show, fxas2100x_enable_store); +static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxas2100x_poll_delay_show, fxas2100x_poll_delay_store); +static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxas2100x_position_show, fxas2100x_position_store); + +static struct attribute *fxas2100x_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_poll_delay.attr, + &dev_attr_position.attr, + NULL +}; + +static const struct attribute_group fxas2100x_attr_group = { + .attrs = fxas2100x_attributes, +}; + +static void fxas2100x_poll(struct input_polled_dev *dev) +{ + struct fxas2100x_data *pdata = g_fxas2100x_data; + struct input_dev *idev = pdata->input_polled->input; + struct fxas2100x_data_axis data; + int ret; + + if (!(atomic_read(&pdata->active_poll))) + return; + + ret = fxas2100x_read_data(pdata, &data); + if (!ret) { + fxas2100x_data_convert(pdata, &data); + input_report_abs(idev, ABS_X, data.x); + input_report_abs(idev, ABS_Y, data.y); + input_report_abs(idev, ABS_Z, data.z); + input_sync(idev); + } +} + +static int fxas2100x_register_polled_device(struct fxas2100x_data *pdata) +{ + struct input_polled_dev *ipoll_dev; + struct input_dev *idev; + int error; + + ipoll_dev = input_allocate_polled_device(); + if (!ipoll_dev) + return -ENOMEM; + + ipoll_dev->private = pdata; + ipoll_dev->poll = fxas2100x_poll; + ipoll_dev->poll_interval = FXAS2100X_POLL_INTERVAL; + ipoll_dev->poll_interval_min = FXAS2100X_POLL_MIN; + ipoll_dev->poll_interval_max = FXAS2100X_POLL_MAX; + idev = ipoll_dev->input; + idev->name = FXAS2100X_DRIVER; + idev->id.bustype = BUS_I2C; + idev->dev.parent = &pdata->client->dev; + + idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(idev, ABS_X, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0); + input_set_abs_params(idev, ABS_Y, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0); + input_set_abs_params(idev, ABS_Z, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0); + + error = input_register_polled_device(ipoll_dev); + if (error) { + input_free_polled_device(ipoll_dev); + return error; + } + + pdata->input_polled = ipoll_dev; + return 0; +} + +static int fxas2100x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result, chip_id; + struct fxas2100x_data *pdata; + struct i2c_adapter *adapter; + + adapter = to_i2c_adapter(client->dev.parent); + result = i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA); + if (!result) + goto err_out; + + chip_id = i2c_smbus_read_byte_data(client, FXAS2100X_WHO_AM_I); + if (chip_id != FXAS21000_CHIP_ID && chip_id != FXAS21002_CHID_ID_1 && + chip_id != FXAS21002_CHID_ID_2) { + dev_err(&client->dev, + "read chip ID 0x%x is not equal to 0x%x for fxas21000 or 0x%x/0x%x fxas21002!\n", + chip_id, FXAS21000_CHIP_ID, FXAS21002_CHID_ID_1, FXAS21002_CHID_ID_2); + result = -EINVAL; + goto err_out; + } + + pdata = kzalloc(sizeof(struct fxas2100x_data), GFP_KERNEL); + if (!pdata) { + result = -ENOMEM; + dev_err(&client->dev, "alloc data memory error!\n"); + goto err_out; + } + + /* Initialize the FXAS2100X chip */ + g_fxas2100x_data = pdata; + pdata->client = client; + pdata->chip_id = chip_id; + atomic_set(&pdata->delay, FXAS2100X_DELAY_DEFAULT); + atomic_set(&pdata->position, FXAS2100X_POSITION_DEFAULT); + i2c_set_clientdata(client, pdata); + result = misc_register(&fxas2100x_device); + if (result != 0) { + dev_err(&client->dev, "register acc miscdevice error"); + goto err_regsiter_misc; + } + + /* for debug */ + if (client->irq <= 0) { + result = fxas2100x_register_polled_device(g_fxas2100x_data); + if (result) + dev_err(&client->dev, + "IRQ GPIO conf. error %d, error %d\n", + client->irq, result); + } + + result = sysfs_create_group(&fxas2100x_device.this_device->kobj, + &fxas2100x_attr_group); + if (result) { + dev_err(&client->dev, "create device file failed!\n"); + result = -EINVAL; + goto err_create_sysfs; + } + fxas2100x_device_init(client); + dev_info(&client->dev, "fxas2100x device driver probe successfully\n"); + return 0; +err_create_sysfs: + misc_deregister(&fxas2100x_device); +err_regsiter_misc: + kfree(pdata); +err_out: + return result; +} + +static int fxas2100x_remove(struct i2c_client *client) +{ + struct fxas2100x_data *pdata = i2c_get_clientdata(client); + fxas2100x_device_stop(client); + if (client->irq <= 0) { + input_unregister_polled_device(pdata->input_polled); + input_free_polled_device(pdata->input_polled); + } + misc_deregister(&fxas2100x_device); + if (pdata != NULL) + kfree(pdata); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int fxas2100x_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fxas2100x_data *pdata = i2c_get_clientdata(client); + + if (atomic_read(&pdata->active)) + fxas2100x_device_stop(client); + return 0; +} + +static int fxas2100x_resume(struct device *dev) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fxas2100x_data *pdata = i2c_get_clientdata(client); + + if (atomic_read(&pdata->active)) { + val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1); + val &= ~0x03; + val |= 0x02; + i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val); + } + return 0; + +} +#endif + +static const struct i2c_device_id fxas2100x_id[] = { + { "fxas2100x", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, fxas2100x_id); + +static SIMPLE_DEV_PM_OPS(fxas2100x_pm_ops, fxas2100x_suspend, fxas2100x_resume); +static struct i2c_driver fxas2100x_driver = { + .driver = { + .name = FXAS2100X_DRIVER, + .owner = THIS_MODULE, + .pm = &fxas2100x_pm_ops, + }, + .probe = fxas2100x_probe, + .remove = fxas2100x_remove, + .id_table = fxas2100x_id, +}; + +module_i2c_driver(fxas2100x_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("FXAS2100X 3-Axis Gyrosope Sensor driver"); +MODULE_LICENSE("GPL"); From 443ea784ee70a2e9f5b1b3ee66ba2980300055a8 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 5 May 2015 18:58:55 +0800 Subject: [PATCH 0026/3047] MLK-10835-2 misc: fxos8700: add Freescale FXOS8700 6-Axis Acc and Mag Combo Sensor Add Freescale FXOS8700 6-Axis Acc and Mag Combo Sensor Signed-off-by: Fugang Duan (cherry picked from commit: c0ca56bbf3f8503a858d15bb14f27652ae6612eb) --- drivers/misc/Kconfig | 10 + drivers/misc/Makefile | 1 + drivers/misc/fxos8700.c | 919 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 930 insertions(+) create mode 100644 drivers/misc/fxos8700.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index fcd4d7c4a5a486..1a1cd2e7c590c6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -335,6 +335,16 @@ config ISL29020 This driver can also be built as a module. If so, the module will be called isl29020. +config SENSORS_FXOS8700 + tristate "Freescale FXOS8700 M+G combo sensor" + depends on I2C && SYSFS + help + If you say yes here you get support for the Freescale FXOS8700 + m+g combo sensor. + + This driver can also be built as a module. If so, the module + will be called fxos8700. + config SENSORS_FXAS2100X tristate "Freescale FXAS2100X gyroscope sensor" depends on I2C && SYSFS diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 88cc6af7c8df5a..9c7cce275dc8b0 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o +obj-$(CONFIG_SENSORS_FXOS8700) += fxos8700.o obj-$(CONFIG_SENSORS_FXAS2100X) += fxas2100x.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o diff --git a/drivers/misc/fxos8700.c b/drivers/misc/fxos8700.c new file mode 100644 index 00000000000000..fdd936cb1fccc0 --- /dev/null +++ b/drivers/misc/fxos8700.c @@ -0,0 +1,919 @@ +/* + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*register define*/ +#define FXOS8700_STATUS 0x00 +#define FXOS8700_OUT_X_MSB 0x01 +#define FXOS8700_OUT_X_LSB 0x02 +#define FXOS8700_OUT_Y_MSB 0x03 +#define FXOS8700_OUT_Y_LSB 0x04 +#define FXOS8700_OUT_Z_MSB 0x05 +#define FXOS8700_OUT_Z_LSB 0x06 +#define FXOS8700_F_SETUP 0x09 +#define FXOS8700_TRIG_CFG 0x0a +#define FXOS8700_SYSMOD 0x0B +#define FXOS8700_INT_SOURCE 0x0c +#define FXOS8700_WHO_AM_I 0x0d +#define FXOS8700_XYZ_DATA_CFG 0x0e +#define FXOS8700_HP_FILTER_CUTOFF 0x0f +#define FXOS8700_PL_STATUS 0x10 +#define FXOS8700_PL_CFG 0x11 +#define FXOS8700_PL_COUNT 0x12 +#define FXOS8700_PL_BF_ZCOMP 0x13 +#define FXOS8700_PL_P_L_THS_REG 0x14 +#define FXOS8700_FFMT_CFG 0x15 +#define FXOS8700_FFMT_SRC 0x16 +#define FXOS8700_FFMT_THS 0x17 +#define FXOS8700_FFMT_COUNT 0x18 +#define FXOS8700_TRANSIDENT1_CFG 0x1d +#define FXOS8700_TRANSIDENT1_SRC 0x1e +#define FXOS8700_TRANSIDENT1_THS 0x1f +#define FXOS8700_TRANSIDENT1_COUNT 0x20 +#define FXOS8700_PULSE_CFG 0x21 +#define FXOS8700_PULSE_SRC 0x22 +#define FXOS8700_PULSE_THSX 0x23 +#define FXOS8700_PULSE_THSY 0x24 +#define FXOS8700_PULSE_THSZ 0x25 +#define FXOS8700_PULSE_TMLT 0x26 +#define FXOS8700_PULSE_LTCY 0x27 +#define FXOS8700_PULSE_WIND 0x28 +#define FXOS8700_ATSLP_COUNT 0x29 +#define FXOS8700_CTRL_REG1 0x2a +#define FXOS8700_CTRL_REG2 0x2b +#define FXOS8700_CTRL_REG3 0x2c +#define FXOS8700_CTRL_REG4 0x2d +#define FXOS8700_CTRL_REG5 0x2e +#define FXOS8700_OFF_X 0x2f +#define FXOS8700_OFF_Y 0x30 +#define FXOS8700_OFF_Z 0x31 +#define FXOS8700_M_DR_STATUS 0x32 +#define FXOS8700_M_OUT_X_MSB 0x33 +#define FXOS8700_M_OUT_X_LSB 0x34 +#define FXOS8700_M_OUT_Y_MSB 0x35 +#define FXOS8700_M_OUT_Y_LSB 0x36 +#define FXOS8700_M_OUT_Z_MSB 0x37 +#define FXOS8700_M_OUT_Z_LSB 0x38 +#define FXOS8700_CMP_X_MSB 0x39 +#define FXOS8700_CMP_X_LSB 0x3a +#define FXOS8700_CMP_Y_MSB 0x3b +#define FXOS8700_CMP_Y_LSB 0x3c +#define FXOS8700_CMP_Z_MSB 0x3d +#define FXOS8700_CMP_Z_LSB 0x3e +#define FXOS8700_M_OFF_X_MSB 0x3f +#define FXOS8700_M_OFF_X_LSB 0x40 +#define FXOS8700_M_OFF_Y_MSB 0x41 +#define FXOS8700_M_OFF_Y_LSB 0x42 +#define FXOS8700_M_OFF_Z_MSB 0x43 +#define FXOS8700_M_OFF_Z_LSB 0x44 +#define FXOS8700_MAX_X_MSB 0x45 +#define FXOS8700_MAX_X_LSB 0x46 +#define FXOS8700_MAX_Y_MSB 0x47 +#define FXOS8700_MAX_Y_LSB 0x48 +#define FXOS8700_MAX_Z_MSB 0x49 +#define FXOS8700_MAX_Z_LSB 0x4a +#define FXOS8700_MIN_X_MSB 0x4b +#define FXOS8700_MIN_X_LSB 0x4c +#define FXOS8700_MIN_Y_MSB 0x4d +#define FXOS8700_MIN_Y_LSB 0x4e +#define FXOS8700_MIN_Z_MSB 0x4f +#define FXOS8700_MIN_Z_LSB 0x50 +#define FXOS8700_M_TEMP 0x51 +#define FXOS8700_MAG_THS_CFG 0x52 +#define FXOS8700_MAG_THS_SRC 0x53 +#define FXOS8700_MAG_THS_THS_X1 0x54 +#define FXOS8700_MAG_THS_THS_X0 0x55 +#define FXOS8700_MAG_THS_THS_Y1 0x56 +#define FXOS8700_MAG_THS_THS_Y0 0x57 +#define FXOS8700_MAG_THS_THS_Z1 0x58 +#define FXOS8700_MAG_THS_THS_Z0 0x59 +#define FXOS8700_MAG_THS_CUNT 0x5a +#define FXOS8700_M_CTRL_REG1 0x5b +#define FXOS8700_M_CTRL_REG2 0x5c +#define FXOS8700_M_CTRL_REG3 0x5d +#define FXOS8700_M_INT_SOURCE 0x5e +#define FXOS8700_G_VECM_CFG 0x5f +#define FXOS8700_G_VECM_THS_MSB 0x60 +#define FXOS8700_G_VECM_THS_LSB 0x61 +#define FXOS8700_G_VECM_CNT 0x62 +#define FXOS8700_G_VECM_INITX_MSB 0x63 +#define FXOS8700_G_VECM_INITX_LSB 0x64 +#define FXOS8700_G_VECM_INITY_MSB 0x65 +#define FXOS8700_G_VECM_INITY_LSB 0x66 +#define FXOS8700_G_VECM_INITZ_MSB 0x67 +#define FXOS8700_G_VECM_INITZ_LSB 0x68 +#define FXOS8700_M_VECM_CFG 0x69 +#define FXOS8700_M_VECM_THS_MSB 0x6a +#define FXOS8700_M_VECM_THS_LSB 0x6b +#define FXOS8700_M_VECM_CNT 0x6d +#define FXOS8700_M_VECM_INITX_MSB 0x6d +#define FXOS8700_M_VECM_INITX_LSB 0x6e +#define FXOS8700_M_VECM_INITY_MSB 0x6f +#define FXOS8700_M_VECM_INITY_LSB 0x70 +#define FXOS8700_M_VECM_INITZ_MSB 0x71 +#define FXOS8700_M_VECM_INITZ_LSB 0x72 +#define FXOS8700_G_FFMT_THS_X1 0x73 +#define FXOS8700_G_FFMT_THS_X0 0x74 +#define FXOS8700_G_FFMT_THS_Y1 0x75 +#define FXOS8700_G_FFMT_THS_Y0 0x76 +#define FXOS8700_G_FFMT_THS_Z1 0x77 +#define FXOS8700_G_FFMT_THS_Z0 0x78 +#define FXOS8700_G_TRAN_INIT_MSB 0x79 +#define FXOS8700_G_TRAN_INIT_LSB_X 0x7a +#define FXOS8700_G_TRAN_INIT_LSB_Y 0x7b +#define FXOS8700_G_TRAN_INIT_LSB_Z 0x7d +#define FXOS8700_TM_NVM_LOCK 0x7e +#define FXOS8700_NVM_DATA0_35 0x80 +#define FXOS8700_NVM_DATA_BNK3 0xa4 +#define FXOS8700_NVM_DATA_BNK2 0xa5 +#define FXOS8700_NVM_DATA_BNK1 0xa6 +#define FXOS8700_NVM_DATA_BNK0 0xa7 + +#define SENSOR_IOCTL_BASE 'S' +#define SENSOR_GET_MODEL_NAME _IOR(SENSOR_IOCTL_BASE, 0, char *) +#define SENSOR_GET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 2, int) +#define SENSOR_SET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 3, int) +#define SENSOR_GET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 4, int) +#define SENSOR_SET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 5, int) +#define SENSOR_GET_RAW_DATA _IOR(SENSOR_IOCTL_BASE, 6, short[3]) + +#define FXOS8700_I2C_ADDR 0x1E +#define FXOS8700_DEVICE_ID 0xC7 +#define FXOS8700_PRE_DEVICE_ID 0xC4 +#define FXOS8700_DATA_BUF_SIZE 6 +#define FXOS8700_DELAY_DEFAULT 200 /* msecs */ +#define FXOS8700_POSITION_DEFAULT 1 /* msecs */ + +#define FXOS8700_TYPE_ACC 0x00 +#define FXOS8700_TYPE_MAG 0x01 +#define FXOS8700_STANDBY 0x00 +#define FXOS8700_ACTIVED 0x01 + +#define ABS_STATUS ABS_WHEEL +#define FXOS8700_DRIVER "fxos8700" + +#define ABSMAX_ACC_VAL 0x01FF +#define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL) +#define FXOS8700_POLL_INTERVAL 400 +#define FXOS8700_POLL_MAX 800 +#define FXOS8700_POLL_MIN 100 + + +struct fxos8700_data_axis { + short x; + short y; + short z; +}; + +struct fxos8700_data { + struct i2c_client *client; + struct input_polled_dev *input_polled; + struct miscdevice *acc_miscdev; + struct miscdevice *mag_miscdev; + atomic_t acc_delay; + atomic_t mag_delay; + atomic_t acc_active; + atomic_t acc_active_poll; + atomic_t mag_active_poll; + atomic_t mag_active; + atomic_t position; +}; + +static struct fxos8700_data *g_fxos8700_data; +static int fxos8700_position_settings[8][3][3] = { + { { 0, -1, 0}, { 1, 0, 0}, {0, 0, 1} }, + { {-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} }, + { { 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, + { { 1, 0, 0}, { 0, 1, 0}, {0, 0, 1} }, + { { 0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, + { {-1, 0, 0}, { 0, 1, 0}, {0, 0, -1} }, + { { 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} }, + { { 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} }, +}; + +static int fxos8700_data_convert(struct fxos8700_data_axis *axis_data, int position) +{ + short rawdata[3], data[3]; + int i, j; + if (position < 0 || position > 7) + position = 0; + rawdata[0] = axis_data->x; + rawdata[1] = axis_data->y; + rawdata[2] = axis_data->z; + for (i = 0; i < 3 ; i++) { + data[i] = 0; + for (j = 0; j < 3; j++) + data[i] += rawdata[j] * fxos8700_position_settings[position][i][j]; + } + + axis_data->x = data[0]; + axis_data->y = data[1]; + axis_data->z = data[2]; + return 0; +} + +static int fxos8700_change_mode(struct i2c_client *client, int type, int active) +{ + u8 data; + int acc_act, mag_act; + struct fxos8700_data *pdata = i2c_get_clientdata(client); + + acc_act = atomic_read(&pdata->acc_active); + mag_act = atomic_read(&pdata->mag_active); + data = i2c_smbus_read_byte_data(client, FXOS8700_CTRL_REG1); + if (type == FXOS8700_TYPE_ACC) + acc_act = active; + else + mag_act = active; + if (acc_act == FXOS8700_ACTIVED || mag_act == FXOS8700_ACTIVED) + data |= 0x01; + else + data &= ~0x01; + i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, data); + + return 0; +} + +static int fxos8700_set_odr(struct i2c_client *client, int type, int delay) +{ + return 0; +} + +static int fxos8700_device_init(struct i2c_client *client) +{ + int result; + struct fxos8700_data *pdata = i2c_get_clientdata(client); + + /* standby mode */ + result = i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x00); + if (result < 0) + goto out; + result = i2c_smbus_write_byte_data(client, FXOS8700_M_CTRL_REG1, 0x1F); + if (result < 0) + goto out; + result = i2c_smbus_write_byte_data(client, FXOS8700_M_CTRL_REG2, 0x5c); + if (result < 0) + goto out; + result = i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x03 << 3); + if (result < 0) + goto out; + + atomic_set(&pdata->acc_active, FXOS8700_STANDBY); + atomic_set(&pdata->mag_active, FXOS8700_STANDBY); + atomic_set(&pdata->position, FXOS8700_POSITION_DEFAULT); + return 0; +out: + dev_err(&client->dev, "Error when init fxos8700 device:(%d)", result); + return result; +} + +static int fxos8700_device_stop(struct i2c_client *client) +{ + i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x00); + return 0; +} + +static int +fxos8700_read_data(struct i2c_client *client, struct fxos8700_data_axis *data, int type) +{ + u8 tmp_data[FXOS8700_DATA_BUF_SIZE]; + int ret; + u8 reg; + + if (type == FXOS8700_TYPE_ACC) + reg = FXOS8700_OUT_X_MSB; + else + reg = FXOS8700_M_OUT_X_MSB; + + ret = i2c_smbus_read_i2c_block_data(client, reg, FXOS8700_DATA_BUF_SIZE, tmp_data); + if (ret < FXOS8700_DATA_BUF_SIZE) { + dev_err(&client->dev, "i2c block read %s failed\n", + (type == FXOS8700_TYPE_ACC ? "acc" : "mag")); + return -EIO; + } + data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; + data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; + data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; + return 0; +} + +static long fxos8700_acc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct fxos8700_data *pdata = file->private_data; + void __user *argp = (void __user *)arg; + struct fxos8700_data_axis data; + long ret = 0; + short sdata[3]; + int enable; + int delay; + int position; + + if (!pdata) { + printk(KERN_ERR "fxos8700 struct datt point is NULL."); + return -EFAULT; + } + + switch (cmd) { + case SENSOR_GET_MODEL_NAME: + if (copy_to_user(argp, "FXOS8700 ACC", strlen("FXOS8700 ACC") + 1)) { + printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_GET_POWER_STATUS: + enable = atomic_read(&pdata->acc_active); + if (copy_to_user(argp, &enable, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_SET_POWER_STATUS: + if (copy_from_user(&enable, argp, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + if (pdata->client) { + ret = fxos8700_change_mode(pdata->client, FXOS8700_TYPE_ACC, + enable ? FXOS8700_ACTIVED : FXOS8700_STANDBY); + if (!ret) + atomic_set(&pdata->acc_active, enable); + } + break; + case SENSOR_GET_DELAY_TIME: + delay = atomic_read(&pdata->acc_delay); + if (copy_to_user(argp, &delay, sizeof(delay))) { + printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed."); + return -EFAULT; + } + break; + case SENSOR_SET_DELAY_TIME: + if (copy_from_user(&delay, argp, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_DELAY_TIME copy_to_user failed."); + ret = -EFAULT; + } + if (pdata->client && delay > 0 && delay <= 500) { + ret = fxos8700_set_odr(pdata->client, FXOS8700_TYPE_ACC, delay); + if (!ret) + atomic_set(&pdata->acc_delay, delay); + } + break; + case SENSOR_GET_RAW_DATA: + position = atomic_read(&pdata->position); + ret = fxos8700_read_data(pdata->client, &data, FXOS8700_TYPE_ACC); + if (!ret) { + fxos8700_data_convert(&data, position); + sdata[0] = data.x; + sdata[1] = data.y; + sdata[2] = data.z; + if (copy_to_user(argp, sdata, sizeof(sdata))) { + printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed."); + ret = -EFAULT; + } + } + break; + default: + ret = -1; + } + return ret; +} + +static int fxos8700_acc_open(struct inode *inode, struct file *file) +{ + file->private_data = g_fxos8700_data; + return nonseekable_open(inode, file); +} + +static int fxos8700_acc_release(struct inode *inode, struct file *file) +{ + /* note: releasing the wdt in NOWAYOUT-mode does not stop it */ + return 0; +} + +static const struct file_operations fxos8700_acc_fops = { + .owner = THIS_MODULE, + .open = fxos8700_acc_open, + .release = fxos8700_acc_release, + .unlocked_ioctl = fxos8700_acc_ioctl, +}; + +/* mag char miscdevice */ +static long fxos8700_mag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct fxos8700_data *pdata = file->private_data; + void __user *argp = (void __user *)arg; + struct fxos8700_data_axis data; + long ret = 0; + short sdata[3]; + int enable; + int delay; + int position; + + if (!pdata) { + printk(KERN_ERR "fxos8700 struct datt point is NULL."); + return -EFAULT; + } + + switch (cmd) { + case SENSOR_GET_MODEL_NAME: + if (copy_to_user(argp, "FXOS8700 MAG", strlen("FXOS8700 MAG") + 1)) { + printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_GET_POWER_STATUS: + enable = atomic_read(&pdata->mag_active); + if (copy_to_user(argp, &enable, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_SET_POWER_STATUS: + if (copy_from_user(&enable, argp, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + if (pdata->client) { + ret = fxos8700_change_mode(pdata->client, FXOS8700_TYPE_MAG, + enable ? FXOS8700_ACTIVED : FXOS8700_STANDBY); + if (!ret) + atomic_set(&pdata->mag_active, enable); + } + break; + case SENSOR_GET_DELAY_TIME: + delay = atomic_read(&pdata->mag_delay); + if (copy_to_user(argp, &delay, sizeof(delay))) { + printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed."); + return -EFAULT; + } + break; + case SENSOR_SET_DELAY_TIME: + if (copy_from_user(&delay, argp, sizeof(int))) { + printk(KERN_ERR "SENSOR_SET_DELAY_TIME copy_to_user failed."); + ret = -EFAULT; + } + if (pdata->client && delay > 0 && delay <= 500) { + ret = fxos8700_set_odr(pdata->client, FXOS8700_TYPE_MAG, delay); + if (!ret) + atomic_set(&pdata->mag_delay, delay); + } + break; + case SENSOR_GET_RAW_DATA: + position = atomic_read(&pdata->position); + ret = fxos8700_read_data(pdata->client, &data, FXOS8700_TYPE_MAG); + if (!ret) { + fxos8700_data_convert(&data, position); + sdata[0] = data.x; + sdata[1] = data.y; + sdata[2] = data.z; + if (copy_to_user(argp, sdata, sizeof(sdata))) { + printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed."); + ret = -EFAULT; + } + } + break; + default: + ret = -1; + } + return ret; +} + +static int fxos8700_mag_open(struct inode *inode, struct file *file) +{ + file->private_data = g_fxos8700_data; + return nonseekable_open(inode, file); +} + +static int fxos8700_mag_release(struct inode *inode, struct file *file) +{ + /* note: releasing the wdt in NOWAYOUT-mode does not stop it */ + return 0; +} + +static const struct file_operations fxos8700_mag_fops = { + .owner = THIS_MODULE, + .open = fxos8700_mag_open, + .release = fxos8700_mag_release, + .unlocked_ioctl = fxos8700_mag_ioctl, +}; + +static struct miscdevice fxos8700_acc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "FreescaleAccelerometer", + .fops = &fxos8700_acc_fops, +}; + +static struct miscdevice fxos8700_mag_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "FreescaleMagnetometer", + .fops = &fxos8700_mag_fops, +}; + +static ssize_t fxos8700_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct fxos8700_data *pdata = g_fxos8700_data; + int enable = 0; + + if (pdata->acc_miscdev == misc_dev) + enable = atomic_read(&pdata->acc_active); + if (pdata->mag_miscdev == misc_dev) + enable = atomic_read(&pdata->mag_active); + + return sprintf(buf, "%d\n", enable); +} + +static ssize_t fxos8700_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct fxos8700_data *pdata = g_fxos8700_data; + struct i2c_client *client = pdata->client; + unsigned long enable; + int type; + int ret; + + if (kstrtoul(buf, 10, &enable) < 0) + return -EINVAL; + + if (misc_dev == pdata->acc_miscdev) + type = FXOS8700_TYPE_ACC; + if (misc_dev == pdata->mag_miscdev) + type = FXOS8700_TYPE_MAG; + enable = (enable > 0 ? FXOS8700_ACTIVED : FXOS8700_STANDBY); + ret = fxos8700_change_mode(client, type, enable); + if (!ret) { + if (type == FXOS8700_TYPE_ACC) { + atomic_set(&pdata->acc_active, enable); + atomic_set(&pdata->acc_active_poll, enable); + } else { + atomic_set(&pdata->mag_active, enable); + atomic_set(&pdata->mag_active_poll, enable); + } + } + return count; +} + +static ssize_t fxos8700_poll_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct fxos8700_data *pdata = g_fxos8700_data; + int poll_delay = 0; + + if (pdata->acc_miscdev == misc_dev) + poll_delay = atomic_read(&pdata->acc_delay); + if (pdata->mag_miscdev == misc_dev) + poll_delay = atomic_read(&pdata->mag_delay); + + return sprintf(buf, "%d\n", poll_delay); +} + + +static ssize_t fxos8700_poll_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct fxos8700_data *pdata = g_fxos8700_data; + struct i2c_client *client = pdata->client; + unsigned long delay; + int type; + int ret; + + if (kstrtoul(buf, 10, &delay) < 0) + return -EINVAL; + + if (misc_dev == pdata->acc_miscdev) + type = FXOS8700_TYPE_ACC; + if (misc_dev == pdata->mag_miscdev) + type = FXOS8700_TYPE_MAG; + ret = fxos8700_set_odr(client, type, delay); + if (!ret) { + if (type == FXOS8700_TYPE_ACC) + atomic_set(&pdata->acc_delay, delay); + else + atomic_set(&pdata->mag_delay, delay); + } + return count; +} + +static ssize_t fxos8700_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxos8700_data *pdata = g_fxos8700_data; + unsigned long position = atomic_read(&pdata->position); + + return sprintf(buf, "%ld\n", position); +} + +static ssize_t fxos8700_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long position; + struct fxos8700_data *pdata = g_fxos8700_data; + + if (kstrtoul(buf, 10, &position) < 0) + return -EINVAL; + + atomic_set(&pdata->position, position); + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxos8700_enable_show, fxos8700_enable_store); +static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxos8700_poll_delay_show, fxos8700_poll_delay_store); +static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxos8700_position_show, fxos8700_position_store); + +static struct attribute *fxos8700_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_poll_delay.attr, + &dev_attr_position.attr, + NULL +}; + +static const struct attribute_group fxos8700_attr_group = { + .attrs = fxos8700_attributes, +}; + +static int fxos8700_register_sysfs_device(struct fxos8700_data *pdata) +{ + struct miscdevice *misc_dev = NULL; + int err = -1; + + /* register sysfs for acc */ + misc_dev = pdata->acc_miscdev; + err = sysfs_create_group(&misc_dev->this_device->kobj, &fxos8700_attr_group); + if (err) + goto out; + + /* register sysfs for mag */ + misc_dev = pdata->mag_miscdev; + err = sysfs_create_group(&misc_dev->this_device->kobj, &fxos8700_attr_group); + if (err) + goto err_register_sysfs; + return 0; +err_register_sysfs: + misc_dev = pdata->acc_miscdev; + sysfs_remove_group(&misc_dev->this_device->kobj, &fxos8700_attr_group); + printk("reigster mag sysfs error\n"); +out: + printk("reigster acc sysfs error\n"); + return err; +} + +static int fxos8700_unregister_sysfs_device(struct fxos8700_data *pdata) +{ + struct miscdevice *misc_dev; + misc_dev = pdata->acc_miscdev; + sysfs_remove_group(&misc_dev->this_device->kobj, &fxos8700_attr_group); + + misc_dev = pdata->mag_miscdev; + sysfs_remove_group(&misc_dev->this_device->kobj, &fxos8700_attr_group); + return 0; +} + +static void fxos8700_report(struct input_polled_dev *dev, int type) +{ + struct fxos8700_data_axis data; + struct fxos8700_data *pdata = g_fxos8700_data; + struct input_dev *idev = pdata->input_polled->input; + int position; + int ret; + + position = atomic_read(&pdata->position); + ret = fxos8700_read_data(pdata->client, &data, type); + if (!ret) { + fxos8700_data_convert(&data, position); + input_report_abs(idev, ABS_X, data.x); + input_report_abs(idev, ABS_Y, data.y); + input_report_abs(idev, ABS_Z, data.z); + input_sync(idev); + } +} + +static void fxos8700_poll(struct input_polled_dev *dev) +{ + struct fxos8700_data *pdata = g_fxos8700_data; + int type; + + if (!(atomic_read(&pdata->acc_active_poll) || + atomic_read(&pdata->mag_active_poll))) + return; + + if (atomic_read(&pdata->acc_active_poll)) + type = FXOS8700_TYPE_ACC; + if (atomic_read(&pdata->mag_active_poll)) + type =FXOS8700_TYPE_MAG; + fxos8700_report(dev, type); +} + +static int fxo8700_register_polled_device(struct fxos8700_data *pdata) +{ + struct input_polled_dev *ipoll_dev; + struct input_dev *idev; + int error; + + ipoll_dev = input_allocate_polled_device(); + if (!ipoll_dev) + return -ENOMEM; + + ipoll_dev->private = pdata; + ipoll_dev->poll = fxos8700_poll; + ipoll_dev->poll_interval = FXOS8700_POLL_INTERVAL; + ipoll_dev->poll_interval_min = FXOS8700_POLL_MIN; + ipoll_dev->poll_interval_max = FXOS8700_POLL_MAX; + idev = ipoll_dev->input; + idev->name = FXOS8700_DRIVER; + idev->id.bustype = BUS_I2C; + idev->dev.parent = &pdata->client->dev; + + idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); + input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); + input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); + + error = input_register_polled_device(ipoll_dev); + if (error) { + input_free_polled_device(ipoll_dev); + return error; + } + + pdata->input_polled = ipoll_dev; + + return 0; +} + +static int fxos8700_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result, client_id; + struct fxos8700_data *pdata; + struct i2c_adapter *adapter; + + adapter = to_i2c_adapter(client->dev.parent); + result = i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA); + if (!result) + goto err_out; + + client_id = i2c_smbus_read_byte_data(client, FXOS8700_WHO_AM_I); + if (client_id != FXOS8700_DEVICE_ID && client_id != FXOS8700_PRE_DEVICE_ID) { + dev_err(&client->dev, + "read chip ID 0x%x is not equal to 0x%x or 0x%x\n", + result, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID); + result = -EINVAL; + goto err_out; + } + pdata = kzalloc(sizeof(struct fxos8700_data), GFP_KERNEL); + if (!pdata) { + result = -ENOMEM; + dev_err(&client->dev, "alloc data memory error!\n"); + goto err_out; + } + g_fxos8700_data = pdata; + pdata->client = client; + atomic_set(&pdata->acc_delay, FXOS8700_DELAY_DEFAULT); + atomic_set(&pdata->mag_delay, FXOS8700_DELAY_DEFAULT); + i2c_set_clientdata(client, pdata); + + result = misc_register(&fxos8700_acc_device); + if (result != 0) { + printk(KERN_ERR "register acc miscdevice error"); + goto err_regsiter_acc_misc; + } + pdata->acc_miscdev = &fxos8700_acc_device; + + result = misc_register(&fxos8700_mag_device); + if (result != 0) { + printk(KERN_ERR "register acc miscdevice error"); + goto err_regsiter_mag_misc; + } + pdata->mag_miscdev = &fxos8700_mag_device; + + /* for debug */ + if (client->irq <= 0) { + result = fxo8700_register_polled_device(g_fxos8700_data); + if (result) + dev_err(&client->dev, + "IRQ GPIO conf. error %d, error %d\n", + client->irq, result); + } + + result = fxos8700_register_sysfs_device(pdata); + if (result) { + dev_err(&client->dev, "create device file failed!\n"); + result = -EINVAL; + goto err_register_sys; + } + fxos8700_device_init(client); + printk("fxos8700 device driver probe successfully"); + return 0; +err_register_sys: + misc_deregister(&fxos8700_mag_device); + pdata->mag_miscdev = NULL; +err_regsiter_mag_misc: + misc_deregister(&fxos8700_acc_device); + pdata->acc_miscdev = NULL; +err_regsiter_acc_misc: + i2c_set_clientdata(client, NULL); + kfree(pdata); +err_out: + return result; +} + +static int fxos8700_remove(struct i2c_client *client) +{ + struct fxos8700_data *pdata = i2c_get_clientdata(client); + if (!pdata) + return 0; + fxos8700_device_stop(client); + if (client->irq <= 0) { + input_unregister_polled_device(pdata->input_polled); + input_free_polled_device(pdata->input_polled); + } + fxos8700_unregister_sysfs_device(pdata); + misc_deregister(&fxos8700_acc_device); + misc_deregister(&fxos8700_mag_device); + kfree(pdata); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int fxos8700_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fxos8700_data *pdata = i2c_get_clientdata(client); + if (atomic_read(&pdata->acc_active) || atomic_read(&pdata->mag_active)) + fxos8700_device_stop(client); + return 0; +} + +static int fxos8700_resume(struct device *dev) +{ + int ret = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fxos8700_data *pdata = i2c_get_clientdata(client); + if (atomic_read(&pdata->acc_active)) + fxos8700_change_mode(client, FXOS8700_TYPE_ACC, FXOS8700_ACTIVED); + if (atomic_read(&pdata->mag_active)) + fxos8700_change_mode(client, FXOS8700_TYPE_MAG, FXOS8700_ACTIVED); + return ret; +} +#endif + +static const struct i2c_device_id fxos8700_id[] = { + {"fxos8700", 0}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, fxos8700_id); + +static SIMPLE_DEV_PM_OPS(fxos8700_pm_ops, fxos8700_suspend, fxos8700_resume); +static struct i2c_driver fxos8700_driver = { + .driver = { + .name = FXOS8700_DRIVER, + .owner = THIS_MODULE, + .pm = &fxos8700_pm_ops, + }, + .probe = fxos8700_probe, + .remove = fxos8700_remove, + .id_table = fxos8700_id, +}; + +module_i2c_driver(fxos8700_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver"); +MODULE_LICENSE("GPL"); From 76fed6b8bb201214f000a416391c28421ad8e1c7 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 5 May 2015 20:36:58 +0800 Subject: [PATCH 0027/3047] MLK-10835-3 input: misc: mpl3115: add Freescale MPL3115 pressure temperature sensor Add Freescale MPL3115 pressure temperature sensor. Signed-off-by: Fugang Duan (cherry picked from commit: a8c2904a442e1aa163b8562e1a940c8755ab3898) --- drivers/input/misc/Kconfig | 10 + drivers/input/misc/Makefile | 1 + drivers/input/misc/mpl3115.c | 348 +++++++++++++++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 drivers/input/misc/mpl3115.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7ffb614ce5664c..ca0171d910dedb 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -831,4 +831,14 @@ config INPUT_HISI_POWERKEY To compile this driver as a module, choose M here: the module will be called hisi_powerkey. +config INPUT_MPL3115 + tristate "MPL3115 pressure temperature sensor" + depends on I2C && SYSFS + help + If you say yes here you get support for the Freescale MPL3115 + pressure temperature sensor. + + This driver can also be built as a module. If so, the module + will be called mpl3115 + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0b6d025f0487a5..9edbafb4111c16 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -78,3 +78,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o +obj-$(CONFIG_INPUT_MPL3115) += mpl3115.o diff --git a/drivers/input/misc/mpl3115.c b/drivers/input/misc/mpl3115.c new file mode 100644 index 00000000000000..b272cf38a645bb --- /dev/null +++ b/drivers/input/misc/mpl3115.c @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2010-2015 Freescale , Inc. All Rights Reserved. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPL3115_DRV_NAME "mpl3115" +#define ABS_TEMPTERAURE ABS_MISC + +#define INPUT_FUZZ 32 +#define INPUT_FLAT 32 +#define MPL_ACTIVED 1 +#define MPL_STANDBY 0 +#define POLL_INTERVAL_MAX 500 +#define POLL_INTERVAL 100 +#define POLL_INTERVAL_MIN 1 +#define MPL3115_ID 0xc4 +#define MPLL_ACTIVE_MASK 0x01 +#define MPL3115_STATUS_DR 0x08 + +/* MPL3115A register address */ +#define MPL3115_STATUS 0x00 +#define MPL3115_PRESSURE_DATA 0x01 +#define MPL3115_DR_STATUS 0x06 +#define MPL3115_DELTA_DATA 0x07 +#define MPL3115_WHO_AM_I 0x0c +#define MPL3115_FIFO_STATUS 0x0d +#define MPL3115_FIFO_DATA 0x0e +#define MPL3115_FIFO_SETUP 0x0e +#define MPL3115_TIME_DELAY 0x10 +#define MPL3115_SYS_MODE 0x11 +#define MPL3115_INT_SORCE 0x12 +#define MPL3115_PT_DATA_CFG 0x13 +#define MPL3115_BAR_IN_MSB 0x14 +#define MPL3115_P_ARLARM_MSB 0x16 +#define MPL3115_T_ARLARM 0x18 +#define MPL3115_P_ARLARM_WND_MSB 0x19 +#define MPL3115_T_ARLARM_WND 0x1b +#define MPL3115_P_MIN_DATA 0x1c +#define MPL3115_T_MIN_DATA 0x1f +#define MPL3115_P_MAX_DATA 0x21 +#define MPL3115_T_MAX_DATA 0x24 +#define MPL3115_CTRL_REG1 0x26 +#define MPL3115_CTRL_REG2 0x27 +#define MPL3115_CTRL_REG3 0x28 +#define MPL3115_CTRL_REG4 0x29 +#define MPL3115_CTRL_REG5 0x2a +#define MPL3115_OFFSET_P 0x2b +#define MPL3115_OFFSET_T 0x2c +#define MPL3115_OFFSET_H 0x2d + +#define DATA_SHIFT_BIT(data, bit) ((data << bit) & (0xff << bit)) + +struct mpl3115_data { + struct i2c_client *client; + struct input_polled_dev *poll_dev; + struct mutex data_lock; + int active; +}; + +static int mpl3115_i2c_read(struct i2c_client *client, u8 reg, u8 *values, u8 length) +{ + return i2c_smbus_read_i2c_block_data(client, reg, length, values); +} + +static int mpl3115_i2c_write(struct i2c_client *client, u8 reg, const u8 *values, u8 length) +{ + return i2c_smbus_write_i2c_block_data(client, reg, length, values); +} + +static ssize_t mpl3115_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int val; + u8 sysmode; + + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mpl3115_data *pdata = (struct mpl3115_data *)(poll_dev->private); + struct i2c_client *client = pdata->client; + mutex_lock(&pdata->data_lock); + mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &sysmode, 1); + sysmode &= MPLL_ACTIVE_MASK; + val = (sysmode ? 1 : 0); + mutex_unlock(&pdata->data_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t mpl3115_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret, enable; + u8 val; + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mpl3115_data *pdata = (struct mpl3115_data *)(poll_dev->private); + struct i2c_client *client = pdata->client; + + enable = simple_strtoul(buf, NULL, 10); + mutex_lock(&pdata->data_lock); + mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &val, 1); + if (enable && pdata->active == MPL_STANDBY) { + val |= MPLL_ACTIVE_MASK; + ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1); + if (!ret) + pdata->active = MPL_ACTIVED; + printk("mpl3115 set active\n"); + } else if (!enable && pdata->active == MPL_ACTIVED) { + val &= ~MPLL_ACTIVE_MASK; + ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1); + if (!ret) + pdata->active = MPL_STANDBY; + printk("mpl3115 set inactive\n"); + } + mutex_unlock(&pdata->data_lock); + + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, mpl3115_enable_show, mpl3115_enable_store); + +static struct attribute *mpl3115_attributes[] = { + &dev_attr_enable.attr, + NULL +}; + +static const struct attribute_group mpl3115_attr_group = { + .attrs = mpl3115_attributes, +}; + +static void mpl3115_device_init(struct i2c_client *client) +{ + u8 val[8]; + + val[0] = 0x28; + mpl3115_i2c_write(client, MPL3115_CTRL_REG1, val, 1); +} + +static int mpl3115_read_data(struct i2c_client *client, int *pres, short *temp) +{ + u8 tmp[5]; + + mpl3115_i2c_read(client, MPL3115_PRESSURE_DATA, tmp, 5); + *pres = (DATA_SHIFT_BIT(tmp[0], 24) | DATA_SHIFT_BIT(tmp[1], 16) | DATA_SHIFT_BIT(tmp[2], 8)) >> 12; + *temp = (DATA_SHIFT_BIT(tmp[3], 8) | DATA_SHIFT_BIT(tmp[4], 0)) >> 4; + return 0; +} + +static void report_abs(struct mpl3115_data *pdata) +{ + struct input_dev *idev; + int pressure = 0; + short temperature = 0; + + mutex_lock(&pdata->data_lock); + if (pdata->active == MPL_STANDBY) + goto out; + idev = pdata->poll_dev->input; + mpl3115_read_data(pdata->client, &pressure, &temperature); + input_report_abs(idev, ABS_PRESSURE, pressure); + input_report_abs(idev, ABS_TEMPTERAURE, temperature); + input_sync(idev); +out: + mutex_unlock(&pdata->data_lock); +} + +static void mpl3115_dev_poll(struct input_polled_dev *dev) +{ + struct mpl3115_data *pdata = (struct mpl3115_data *)dev->private; + + report_abs(pdata); +} + +static int mpl3115_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result, client_id; + struct input_dev *idev; + struct i2c_adapter *adapter; + struct mpl3115_data *pdata; + adapter = to_i2c_adapter(client->dev.parent); + result = i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA); + if (!result) + goto err_out; + + client_id = i2c_smbus_read_byte_data(client, MPL3115_WHO_AM_I); + printk("read mpl3115 chip id 0x%x\n", client_id); + if (client_id != MPL3115_ID) { + dev_err(&client->dev, + "read chip ID 0x%x is not equal to 0x%x!\n", + result, MPL3115_ID); + result = -EINVAL; + goto err_out; + } + pdata = kzalloc(sizeof(struct mpl3115_data), GFP_KERNEL); + if (!pdata) + goto err_out; + pdata->client = client; + i2c_set_clientdata(client, pdata); + mutex_init(&pdata->data_lock); + pdata->poll_dev = input_allocate_polled_device(); + if (!pdata->poll_dev) { + result = -ENOMEM; + dev_err(&client->dev, "alloc poll device failed!\n"); + goto err_alloc_data; + } + pdata->poll_dev->poll = mpl3115_dev_poll; + pdata->poll_dev->private = pdata; + pdata->poll_dev->poll_interval = POLL_INTERVAL; + pdata->poll_dev->poll_interval_min = POLL_INTERVAL_MIN; + pdata->poll_dev->poll_interval_max = POLL_INTERVAL_MAX; + idev = pdata->poll_dev->input; + idev->name = MPL3115_DRV_NAME; + idev->id.bustype = BUS_I2C; + idev->evbit[0] = BIT_MASK(EV_ABS); + + input_set_abs_params(idev, ABS_PRESSURE, -0x7FFFFFFF, 0x7FFFFFFF, 0, 0); + input_set_abs_params(idev, ABS_TEMPTERAURE, -0x7FFFFFFF, 0x7FFFFFFF, 0, 0); + result = input_register_polled_device(pdata->poll_dev); + if (result) { + dev_err(&client->dev, "register poll device failed!\n"); + goto error_free_poll_dev; + } + result = sysfs_create_group(&idev->dev.kobj, &mpl3115_attr_group); + if (result) { + dev_err(&client->dev, "create device file failed!\n"); + result = -EINVAL; + goto error_register_polled_device; + } + mpl3115_device_init(client); + printk("mpl3115 device driver probe successfully"); + return 0; +error_register_polled_device: + input_unregister_polled_device(pdata->poll_dev); +error_free_poll_dev: + input_free_polled_device(pdata->poll_dev); +err_alloc_data: + kfree(pdata); +err_out: + return result; +} + +static int mpl3115_stop_chip(struct i2c_client *client) +{ + u8 val; + int ret; + + mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &val, 1); + val &= ~MPLL_ACTIVE_MASK; + ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1); + + return 0; +} +static int mpl3115_start_chip(struct i2c_client *client) +{ + u8 val; + int ret; + + mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &val, 1); + val |= MPLL_ACTIVE_MASK; + ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1); + + return 0; +} +static int mpl3115_remove(struct i2c_client *client) +{ + struct mpl3115_data *pdata = i2c_get_clientdata(client); + struct input_dev *idev = pdata->poll_dev->input; + + mpl3115_stop_chip(client); + sysfs_remove_group(&idev->dev.kobj, &mpl3115_attr_group); + input_unregister_polled_device(pdata->poll_dev); + kfree(pdata); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mpl3115_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mpl3115_data *pdata = i2c_get_clientdata(client); + if (pdata->active == MPL_ACTIVED) + mpl3115_stop_chip(client); + return 0; +} + +static int mpl3115_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mpl3115_data *pdata = i2c_get_clientdata(client); + if (pdata->active == MPL_ACTIVED) + mpl3115_start_chip(client); + return 0; +} +#endif + +static const struct i2c_device_id mpl3115_id[] = { + {MPL3115_DRV_NAME, 0}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, mpl3115_id); + +static SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); +static struct i2c_driver mpl3115_driver = { + .driver = { + .name = MPL3115_DRV_NAME, + .owner = THIS_MODULE, + .pm = &mpl3115_pm_ops, + }, + .probe = mpl3115_probe, + .remove = mpl3115_remove, + .id_table = mpl3115_id, +}; + +module_i2c_driver(mpl3115_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MPL3115 Smart Pressure Sensor driver"); +MODULE_LICENSE("GPL"); From 8267b86e143b1582801e1ebda771c58298a59301 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 6 May 2015 10:02:42 +0800 Subject: [PATCH 0028/3047] MLK-10835-5 ARM: imx_v7_defconfig: enable mpl3115,fxas2100x and fxos8700 in defconfig Enable mpl3115,fxas2100x and fxos8700 sensors in defconfig. Signed-off-by: Fugang Duan (cherry picked from commit: 275be06ee31ffd0b9c2c12fb7e563a6b060bf5a2) --- arch/arm/configs/imx_v7_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index bc9e5ed2ad6732..58791648c09a2e 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -107,6 +107,8 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_SENSORS_FXOS8700=y +CONFIG_SENSORS_FXAS2100X=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y # CONFIG_SCSI_PROC_FS is not set @@ -160,6 +162,7 @@ CONFIG_TOUCHSCREEN_TSC2007=y CONFIG_TOUCHSCREEN_STMPE=y CONFIG_INPUT_MISC=y CONFIG_INPUT_MMA8450=y +CONFIG_INPUT_MPL3115=y CONFIG_SERIO_SERPORT=m # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set From 7c7de1b5dae6b2c0250f9cec56868a02173585ca Mon Sep 17 00:00:00 2001 From: gaopan Date: Tue, 12 May 2015 18:25:29 +0800 Subject: [PATCH 0029/3047] MLK-10893: i2c: imx: add irqf_no_suspend The i2c irq is masked when pcie starts a i2c transfer process during noirq suspend stage. As a result, i2c transfer fails. To solve the problem, IRQF_NO_SUSPEND is added to i2c bus. Signed-off-by: Gao Pan Signed-off-by: Fugang Duan (cherrt picked from commit: ab13b0e11c50021905de00a0f3c0df7e0a36a3f0) --- drivers/i2c/busses/i2c-imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 47fc1f1acff7db..d8ad35813cd92d 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1100,8 +1100,8 @@ static int i2c_imx_probe(struct platform_device *pdev) } /* Request IRQ */ - ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, - pdev->name, i2c_imx); + ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, + IRQF_NO_SUSPEND, pdev->name, i2c_imx); if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", irq); goto clk_disable; From f4a9054ef7d703520fe318023afa200318664e07 Mon Sep 17 00:00:00 2001 From: gaopan Date: Thu, 21 May 2015 14:50:47 +0800 Subject: [PATCH 0030/3047] MLK-10948 input: misc: fxls8471: add motion sensor fxls8471 Add Freescale fxls8471 motion sensor. Signed-off-by: Gao Pan Signed-off-by: Fugang Duan (cherry picked from commit: 20cfe2d9d9305559e35fe2e508d5a70b057ffc70) --- drivers/input/misc/Kconfig | 5 + drivers/input/misc/Makefile | 1 + drivers/input/misc/fxls8471.c | 538 ++++++++++++++++++++++++++++++ drivers/input/misc/fxls8471.h | 93 ++++++ drivers/input/misc/fxls8471_i2c.c | 111 ++++++ 5 files changed, 748 insertions(+) create mode 100644 drivers/input/misc/fxls8471.c create mode 100644 drivers/input/misc/fxls8471.h create mode 100644 drivers/input/misc/fxls8471_i2c.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ca0171d910dedb..d1af3e51ccbced 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -841,4 +841,9 @@ config INPUT_MPL3115 This driver can also be built as a module. If so, the module will be called mpl3115 +config SENSOR_FXLS8471 + tristate "FXLS8471 motion sensor device driver" + depends on I2C + default n + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9edbafb4111c16..275a1e1becbd40 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -79,3 +79,4 @@ obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o obj-$(CONFIG_INPUT_MPL3115) += mpl3115.o +obj-$(CONFIG_SENSOR_FXLS8471) += fxls8471.o fxls8471_i2c.o diff --git a/drivers/input/misc/fxls8471.c b/drivers/input/misc/fxls8471.c new file mode 100644 index 00000000000000..95f027ebb0cf47 --- /dev/null +++ b/drivers/input/misc/fxls8471.c @@ -0,0 +1,538 @@ +/* + * fxls8471.c - Linux kernel modules for 3-Axis Accel sensor + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fxls8471.h" + +#define SENSOR_IOCTL_BASE 'S' +#define SENSOR_GET_MODEL_NAME _IOR(SENSOR_IOCTL_BASE, 0, char *) +#define SENSOR_GET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 2, int) +#define SENSOR_SET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 3, int) +#define SENSOR_GET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 4, int) +#define SENSOR_SET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 5, int) +#define SENSOR_GET_RAW_DATA _IOR(SENSOR_IOCTL_BASE, 6, short[3]) + +#define FXLS8471_POSITION_DEFAULT 2 +#define FXLS8471_DELAY_DEFAULT 200 + +#define FXLS8471_STATUS_ZYXDR 0x08 +#define FXLS8471_BUF_SIZE 6 + +struct fxls8471_data fxls8471_dev; + +static int fxls8471_position_setting[8][3][3] = { + {{0, -1, 0}, {1, 0, 0}, {0, 0, 1} }, + {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1} }, + {{0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, + {{1, 0, 0}, {0, 1, 0}, {0, 0, 1} }, + + {{0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, + {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1} }, + {{0, 1, 0}, {1, 0, 0}, {0, 0, -1} }, + {{1, 0, 0}, {0, -1, 0}, {0, 0, -1} }, +}; + +static int fxls8471_bus_write(struct fxls8471_data *pdata, u8 reg, u8 val) +{ + if (pdata && pdata->write) + return pdata->write(pdata, reg, val); + return -EIO; +} + +static int fxls8471_bus_read(struct fxls8471_data *pdata, u8 reg) +{ + if (pdata && pdata->read) + return pdata->read(pdata, reg); + return -EIO; +} + +static int fxls8471_bus_read_block(struct fxls8471_data *pdata, u8 reg, u8 len, + u8 *val) +{ + if (pdata && pdata->read_block) + return pdata->read_block(pdata, reg, len, val); + return -EIO; +} + +static int fxls8471_data_convert(struct fxls8471_data *pdata, + struct fxls8471_data_axis *axis_data) +{ + short rawdata[3], data[3]; + int i, j; + int position = atomic_read(&pdata->position); + + if (position < 0 || position > 7) + position = 0; + rawdata[0] = axis_data->x; + rawdata[1] = axis_data->y; + rawdata[2] = axis_data->z; + for (i = 0; i < 3; i++) { + data[i] = 0; + for (j = 0; j < 3; j++) + data[i] += + rawdata[j] * + fxls8471_position_setting[position][i][j]; + } + axis_data->x = data[0]; + axis_data->y = data[1]; + axis_data->z = data[2]; + return 0; +} + +static int fxls8471_device_init(struct fxls8471_data *pdata) +{ + int result; + result = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, 0); + if (result < 0) + goto out; + + result = fxls8471_bus_write(pdata, FXLS8471_XYZ_DATA_CFG, MODE_2G); + if (result < 0) + goto out; + + if (pdata->irq) { + result = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG5, 0x01); + if (result < 0) + goto out; + result = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG4, 0x01); + if (result < 0) + goto out; + } + atomic_set(&pdata->active, STANDBY); + return 0; +out: + printk("FXLS8471 device init error\n"); + return result; + +} + +static int fxls8471_change_mode(struct fxls8471_data *pdata, int mode) +{ + u8 val; + int ret; + val = fxls8471_bus_read(pdata, FXLS8471_CTRL_REG1); + if (mode == ACTIVED) + val |= 0x01; + else + val &= (~0x01); + ret = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, val); + return ret; +} + +static int fxls8471_set_delay(struct fxls8471_data *pdata, int delay) +{ + u8 val; + val = fxls8471_bus_read(pdata, FXLS8471_CTRL_REG1); + /* set sensor standby */ + fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, (val & ~0x01)); + val &= ~(0x7 << 3); + if (delay <= 10) + val |= 0x02 << 3; + else if (delay <= 20) + val |= 0x03 << 3; + else if (delay <= 67) + val |= 0x04 << 3; + else + val |= 0x05 << 3; + /* set sensor standby */ + fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, val); + return 0; +} + +static int fxls8471_read_data(struct fxls8471_data *pdata, + struct fxls8471_data_axis *data) +{ + u8 tmp_data[FXLS8471_BUF_SIZE]; + int ret; + ret = fxls8471_bus_read_block(pdata, FXLS8471_OUT_X_MSB, + FXLS8471_BUF_SIZE, tmp_data); + if (ret < FXLS8471_BUF_SIZE) { + printk(KERN_ERR "FXLS8471 read sensor block data error\n"); + return -EIO; + } + data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; + data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; + data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; + return 0; +} + +/* fxls8471 miscdevice */ +static long fxls8471_ioctl(struct file *file, unsigned int reg, + unsigned long arg) +{ + struct fxls8471_data *pdata = file->private_data; + void __user *argp = (void __user *)arg; + long ret = 0; + short sdata[3]; + int enable; + int delay; + struct fxls8471_data_axis data; + if (!pdata) { + printk(KERN_ERR "FXLS8471 struct datt point is NULL."); + return -EFAULT; + } + switch (reg) { + case SENSOR_GET_MODEL_NAME: + if (copy_to_user(argp, "fxls8471", strlen("fxls8471") + 1)) { + printk(KERN_ERR + "SENSOR_GET_MODEL_NAME copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_GET_POWER_STATUS: + enable = atomic_read(&pdata->active); + if (copy_to_user(argp, &enable, sizeof(int))) { + printk(KERN_ERR + "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + break; + case SENSOR_SET_POWER_STATUS: + if (copy_from_user(&enable, argp, sizeof(int))) { + printk(KERN_ERR + "SENSOR_SET_POWER_STATUS copy_to_user failed."); + ret = -EFAULT; + } + if (pdata) { + ret = + fxls8471_change_mode(pdata, + enable ? ACTIVED : STANDBY); + if (!ret) + atomic_set(&pdata->active, enable); + } + break; + case SENSOR_GET_DELAY_TIME: + delay = atomic_read(&pdata->delay); + if (copy_to_user(argp, &delay, sizeof(delay))) { + printk(KERN_ERR + "SENSOR_GET_DELAY_TIME copy_to_user failed."); + return -EFAULT; + } + break; + case SENSOR_SET_DELAY_TIME: + if (copy_from_user(&delay, argp, sizeof(int))) { + printk(KERN_ERR + "SENSOR_GET_DELAY_TIME copy_to_user failed."); + ret = -EFAULT; + } + if (pdata && delay > 0 && delay <= 500) { + ret = fxls8471_set_delay(pdata, delay); + if (!ret) + atomic_set(&pdata->delay, delay); + } + break; + case SENSOR_GET_RAW_DATA: + ret = fxls8471_read_data(pdata, &data); + if (!ret) { + fxls8471_data_convert(pdata, &data); + sdata[0] = data.x; + sdata[1] = data.y; + sdata[2] = data.z; + if (copy_to_user(argp, sdata, sizeof(sdata))) { + printk(KERN_ERR + "SENSOR_GET_RAW_DATA copy_to_user failed."); + ret = -EFAULT; + } + } + break; + default: + ret = -1; + } + return ret; +} + +static int fxls8471_open(struct inode *inode, struct file *file) +{ + file->private_data = &fxls8471_dev; + return nonseekable_open(inode, file); +} + +static int fxls8471_release(struct inode *inode, struct file *file) +{ + /* note: releasing the wdt in NOWAYOUT-mode does not stop it */ + return 0; +} + +static const struct file_operations fxls8471_fops = { + .owner = THIS_MODULE, + .open = fxls8471_open, + .release = fxls8471_release, + .unlocked_ioctl = fxls8471_ioctl, +}; + +static struct miscdevice fxls8471_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "FreescaleAccelerometer", + .fops = &fxls8471_fops, +}; + +static ssize_t fxls8471_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int enable = 0; + enable = atomic_read(&pdata->active); + return sprintf(buf, "%d\n", enable); +} + +static ssize_t fxls8471_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int ret; + unsigned long enable; + + if (kstrtoul(buf, 10, &enable) < 0) + return -EINVAL; + enable = (enable > 0) ? 1 : 0; + ret = fxls8471_change_mode(pdata, (enable > 0 ? ACTIVED : STANDBY)); + if (!ret) { + atomic_set(&pdata->active, enable); + printk(KERN_INFO "mma enable setting active\n"); + } + return count; +} + +static ssize_t fxls8471_poll_delay_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int delay = 0; + delay = atomic_read(&pdata->delay); + return sprintf(buf, "%d\n", delay); +} + +static ssize_t fxls8471_poll_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int ret; + unsigned long delay; + + if (kstrtoul(buf, 10, &delay) < 0) + return -EINVAL; + ret = fxls8471_set_delay(pdata, delay); + if (!ret) + atomic_set(&pdata->delay, delay); + + return count; +} + +static ssize_t fxls8471_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int position = 0; + position = atomic_read(&pdata->position); + return sprintf(buf, "%d\n", position); +} + +static ssize_t fxls8471_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + unsigned long position; + + if (kstrtoul(buf, 10, &position) < 0) + return -EINVAL; + atomic_set(&pdata->position, position); + + return count; +} + +static ssize_t fxls8471_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int ret = 0; + struct fxls8471_data_axis data; + ret = fxls8471_read_data(pdata, &data); + if (!ret) + fxls8471_data_convert(pdata, &data); + return sprintf(buf, "%d,%d,%d\n", data.x, data.y, data.z); +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxls8471_enable_show, fxls8471_enable_store); + +static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxls8471_poll_delay_show, + fxls8471_poll_delay_store); + +static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxls8471_position_show, + fxls8471_position_store); + +static DEVICE_ATTR(data, S_IWUSR | S_IRUGO, fxls8471_data_show, NULL); + +static struct attribute *fxls8471_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_poll_delay.attr, + &dev_attr_position.attr, + &dev_attr_data.attr, + NULL +}; + +static const struct attribute_group fxls8471_attr_group = { + .attrs = fxls8471_attributes, +}; + +static irqreturn_t fxls8471_irq_handler(int irq, void *dev) +{ + int ret; + u8 int_src; + struct fxls8471_data *pdata = (struct fxls8471_data *)dev; + struct fxls8471_data_axis data; + int_src = fxls8471_bus_read(pdata, FXLS8471_INT_SOURCE); + /* data ready interrupt */ + if (int_src & 0x01) { + ret = fxls8471_read_data(pdata, &data); + if (!ret) { + fxls8471_data_convert(pdata, &data); + input_report_abs(pdata->idev, ABS_X, data.x); + input_report_abs(pdata->idev, ABS_Y, data.y); + input_report_abs(pdata->idev, ABS_Z, data.z); + input_sync(pdata->idev); + } + + } + return IRQ_HANDLED; +} + +int fxls8471_driver_init(struct fxls8471_data *pdata) +{ + int result, chip_id; + + chip_id = fxls8471_bus_read(pdata, FXLS8471_WHO_AM_I); + + if (chip_id != FXSL8471_ID) { + printk(KERN_ERR "read sensor who am i (0x%x)error !\n", + chip_id); + result = -EINVAL; + goto err_out; + } + /* Initialize the FXLS8471 chip */ + pdata->chip_id = chip_id; + atomic_set(&pdata->delay, FXLS8471_DELAY_DEFAULT); + atomic_set(&pdata->position, FXLS8471_POSITION_DEFAULT); + result = misc_register(&fxls8471_device); + if (result != 0) { + printk(KERN_ERR "register acc miscdevice error"); + goto err_regsiter_misc; + } + + result = + sysfs_create_group(&fxls8471_device.this_device->kobj, + &fxls8471_attr_group); + if (result) { + printk(KERN_ERR "create device file failed!\n"); + result = -EINVAL; + goto err_create_sysfs; + } + /*create data input device */ + pdata->idev = input_allocate_device(); + if (!pdata->idev) { + result = -ENOMEM; + printk(KERN_ERR "alloc fxls8471 input device failed!\n"); + goto err_alloc_input_device; + } + pdata->idev->name = "FreescaleAccelerometer"; + pdata->idev->id.bustype = BUS_I2C; + pdata->idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(pdata->idev, ABS_X, -0x7fff, 0x7fff, 0, 0); + input_set_abs_params(pdata->idev, ABS_Y, -0x7fff, 0x7fff, 0, 0); + input_set_abs_params(pdata->idev, ABS_Z, -0x7fff, 0x7fff, 0, 0); + result = input_register_device(pdata->idev); + if (result) { + printk(KERN_ERR "register fxls8471 input device failed!\n"); + goto err_register_input_device; + } + if (pdata->irq) { + result = + request_threaded_irq(pdata->irq, NULL, fxls8471_irq_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + pdata->idev->name, pdata); + if (result < 0) { + printk(KERN_ERR "failed to register MMA8x5x irq %d!\n", + pdata->irq); + goto err_register_irq; + } + } + fxls8471_device_init(pdata); + printk("fxls8471 device driver probe successfully\n"); + return 0; +err_register_irq: + input_unregister_device(pdata->idev); +err_register_input_device: + input_free_device(pdata->idev); +err_alloc_input_device: + sysfs_remove_group(&fxls8471_device.this_device->kobj, + &fxls8471_attr_group); +err_create_sysfs: + misc_deregister(&fxls8471_device); +err_regsiter_misc: + kfree(pdata); +err_out: + return result; +} +EXPORT_SYMBOL_GPL(fxls8471_driver_init); + +int fxls8471_driver_remove(struct fxls8471_data *pdata) +{ + fxls8471_change_mode(pdata, STANDBY); + misc_deregister(&fxls8471_device); + if (pdata != NULL) + kfree(pdata); + return 0; +} +EXPORT_SYMBOL_GPL(fxls8471_driver_remove); + +#ifdef CONFIG_PM_SLEEP +int fxls8471_driver_suspend(struct fxls8471_data *pdata) +{ + if (atomic_read(&pdata->active)) + fxls8471_change_mode(pdata, STANDBY); + return 0; +} +EXPORT_SYMBOL_GPL(fxls8471_driver_suspend); + +int fxls8471_driver_resume(struct fxls8471_data *pdata) +{ + if (atomic_read(&pdata->active)) + fxls8471_change_mode(pdata, ACTIVED); + return 0; +} +EXPORT_SYMBOL_GPL(fxls8471_driver_resume); + +#endif diff --git a/drivers/input/misc/fxls8471.h b/drivers/input/misc/fxls8471.h new file mode 100644 index 00000000000000..adb0c31f892c93 --- /dev/null +++ b/drivers/input/misc/fxls8471.h @@ -0,0 +1,93 @@ +/* + * fxls8471.h - Linux kernel modules for 3-Axis Accel sensor + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _FXSL8471_H +#define _FXSL8471_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FXSL8471_ID 0x6a + +/* register enum for fxls8471 registers */ +enum { FXLS8471_STATUS = 0x00, FXLS8471_OUT_X_MSB, FXLS8471_OUT_X_LSB, + FXLS8471_OUT_Y_MSB, FXLS8471_OUT_Y_LSB, FXLS8471_OUT_Z_MSB, + FXLS8471_OUT_Z_LSB, FXLS8471_F_SETUP = + 0x09, FXLS8471_TRIG_CFG, FXLS8471_SYSMOD, + FXLS8471_INT_SOURCE, FXLS8471_WHO_AM_I, + FXLS8471_XYZ_DATA_CFG, FXLS8471_HP_FILTER_CUTOFF, + FXLS8471_PL_STATUS, FXLS8471_PL_CFG, FXLS8471_PL_COUNT, + FXLS8471_PL_BF_ZCOMP, FXLS8471_P_L_THS_REG, + FXLS8471_FF_MT_CFG, FXLS8471_FF_MT_SRC, FXLS8471_FF_MT_THS, + FXLS8471_FF_MT_COUNT, FXLS8471_TRANSIENT_CFG = + 0x1D, FXLS8471_TRANSIENT_SRC, FXLS8471_TRANSIENT_THS, + FXLS8471_TRANSIENT_COUNT, FXLS8471_PULSE_CFG, + FXLS8471_PULSE_SRC, FXLS8471_PULSE_THSX, FXLS8471_PULSE_THSY, + FXLS8471_PULSE_THSZ, FXLS8471_PULSE_TMLT, + FXLS8471_PULSE_LTCY, FXLS8471_PULSE_WIND, + FXLS8471_ASLP_COUNT, FXLS8471_CTRL_REG1, FXLS8471_CTRL_REG2, + FXLS8471_CTRL_REG3, FXLS8471_CTRL_REG4, FXLS8471_CTRL_REG5, + FXLS8471_OFF_X, FXLS8471_OFF_Y, FXLS8471_OFF_Z, + FXLS8471_REG_END, +}; + +enum { STANDBY = 0, ACTIVED, +}; + +enum { MODE_2G = 0, MODE_4G, MODE_8G, +}; + +struct fxls8471_data_axis { + short x; + short y; + short z; +}; + +struct fxls8471_data { + void *bus_priv; + u16 bus_type; + int irq; + s32 (*write)(struct fxls8471_data *pdata, u8 reg, u8 val); + s32 (*read)(struct fxls8471_data *pdata, u8 reg); + s32 (*read_block)(struct fxls8471_data *pdata, u8 reg, u8 len, + u8 *val); + struct input_dev *idev; + atomic_t active; + atomic_t delay; + atomic_t position; + u8 chip_id; +}; + +extern struct fxls8471_data fxls8471_dev; + +int fxls8471_driver_init(struct fxls8471_data *pdata); +int fxls8471_driver_remove(struct fxls8471_data *pdata); +int fxls8471_driver_suspend(struct fxls8471_data *pdata); +int fxls8471_driver_resume(struct fxls8471_data *pdata); + +#endif /* */ diff --git a/drivers/input/misc/fxls8471_i2c.c b/drivers/input/misc/fxls8471_i2c.c new file mode 100644 index 00000000000000..f752ddd0d14b11 --- /dev/null +++ b/drivers/input/misc/fxls8471_i2c.c @@ -0,0 +1,111 @@ +/* + * fxls8471-i2c.c - Linux kernel modules for 3-Axis Smart Orientation + * /Motion Sensor + * Version : 01.00 + * Time : Dec.26, 2012 + * Author : rick zhang + * + * Copyright (C) 2010-2011 Freescale Semiconductor. + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include "fxls8471.h" + +static s32 fxls8471_i2c_write(struct fxls8471_data *pdata, u8 reg, u8 val) +{ + struct i2c_client *client = (struct i2c_client *)pdata->bus_priv; + return i2c_smbus_write_byte_data(client, reg, val); +} + +static int fxls8471_i2c_read(struct fxls8471_data *pdata, u8 reg) +{ + struct i2c_client *client = (struct i2c_client *)pdata->bus_priv; + return i2c_smbus_read_byte_data(client, reg); +} + +static int fxls8471_i2c_read_block(struct fxls8471_data *pdata, u8 reg, u8 len, + u8 *val) +{ + struct i2c_client *client = (struct i2c_client *)pdata->bus_priv; + return i2c_smbus_read_i2c_block_data(client, reg, len, val); +} + +static int fxls8471_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + fxls8471_dev.bus_priv = client; + fxls8471_dev.bus_type = BUS_I2C; + fxls8471_dev.irq = client->irq; + fxls8471_dev.read = fxls8471_i2c_read; + fxls8471_dev.write = fxls8471_i2c_write; + fxls8471_dev.read_block = fxls8471_i2c_read_block; + i2c_set_clientdata(client, &fxls8471_dev); + return fxls8471_driver_init(&fxls8471_dev); +} + +static int fxls8471_i2c_remove(struct i2c_client *client) +{ + return fxls8471_driver_remove(&fxls8471_dev); +} + +#ifdef CONFIG_PM +static int fxls8471_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + return fxls8471_driver_suspend(i2c_get_clientdata(client)); +} + +static int fxls8471_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + return fxls8471_driver_resume(i2c_get_clientdata(client)); +} + +#else /* */ +#define fxls8471_i2c_suspend NULL +#define fxls8471_i2c_resume NULL +#endif /* */ +static const struct i2c_device_id fxls8471_i2c_id[] = { + {"fxls8471", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, fxls8471_i2c_id); + +static SIMPLE_DEV_PM_OPS(fxls8471_pm_ops, fxls8471_i2c_suspend, + fxls8471_i2c_resume); + +static struct i2c_driver fxls8471_i2c_driver = { + .driver = { + .name = "fxls8471", + .owner = THIS_MODULE, + .pm = &fxls8471_pm_ops, + }, + .probe = fxls8471_i2c_probe, + .remove = fxls8471_i2c_remove, + .id_table = fxls8471_i2c_id, +}; + +module_i2c_driver(fxls8471_i2c_driver); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("FXLS8471 3-Axis Acc Sensor driver"); +MODULE_LICENSE("GPL"); From eb088e7228e29b91325afde035622045548e7e6b Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 17:38:14 +0800 Subject: [PATCH 0031/3047] MLK-10947 ARM: imx_v7_defconfig: enable fxls8471 in defconfig Enable fxls8471 in defconfig. Signed-off-by: Gao Pan Signed-off-by: Fugang Duan (cherry picked from commit: 692ff04d68f953d4534f27c6c4529e46b1a48518) --- arch/arm/configs/imx_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 58791648c09a2e..3d8aa95897ac5c 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -163,6 +163,7 @@ CONFIG_TOUCHSCREEN_STMPE=y CONFIG_INPUT_MISC=y CONFIG_INPUT_MMA8450=y CONFIG_INPUT_MPL3115=y +CONFIG_SENSOR_FXLS8471=y CONFIG_SERIO_SERPORT=m # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set From 5a12cacde804ca5d4ba6829b8e93e0bdc1c2067e Mon Sep 17 00:00:00 2001 From: Gao Pan Date: Fri, 3 Jul 2015 16:31:38 +0800 Subject: [PATCH 0032/3047] =?UTF-8?q?MLK-11218:=20misc:=20fxos8700:=20supp?= =?UTF-8?q?ort=20=C2=B12g/=C2=B14g/=C2=B18g=20dynamically?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support ±2g/±4g/±8g dynamically selection for motion sensor fxos8700. Set the sensor mode to standby mode before changing the scale range with the command "echo 0 > enable". The scale range can be changed with the command "echo 0/1/2 > range". Signed-off-by: Gao Pan Signed-off-by: Fugang Duan (cherry picked from commit: 74c9af0a5806fb5c926ffdab3145fc1680fc87e6) --- drivers/misc/fxos8700.c | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/misc/fxos8700.c b/drivers/misc/fxos8700.c index fdd936cb1fccc0..326e2accde1b55 100644 --- a/drivers/misc/fxos8700.c +++ b/drivers/misc/fxos8700.c @@ -188,6 +188,8 @@ #define FXOS8700_POLL_MAX 800 #define FXOS8700_POLL_MIN 100 +enum { MODE_2G = 0, MODE_4G, MODE_8G, +}; struct fxos8700_data_axis { short x; @@ -207,6 +209,7 @@ struct fxos8700_data { atomic_t mag_active_poll; atomic_t mag_active; atomic_t position; + atomic_t range; }; static struct fxos8700_data *g_fxos8700_data; @@ -264,6 +267,14 @@ static int fxos8700_change_mode(struct i2c_client *client, int type, int active) return 0; } +static int fxos8700_change_range(struct i2c_client *client, int range) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, FXOS8700_XYZ_DATA_CFG, range); + + return ret; +} static int fxos8700_set_odr(struct i2c_client *client, int type, int delay) { return 0; @@ -287,10 +298,15 @@ static int fxos8700_device_init(struct i2c_client *client) result = i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x03 << 3); if (result < 0) goto out; + result = i2c_smbus_write_byte_data(client, FXOS8700_XYZ_DATA_CFG, + MODE_2G); + if (result < 0) + goto out; atomic_set(&pdata->acc_active, FXOS8700_STANDBY); atomic_set(&pdata->mag_active, FXOS8700_STANDBY); atomic_set(&pdata->position, FXOS8700_POSITION_DEFAULT); + atomic_set(&pdata->range, MODE_2G); return 0; out: dev_err(&client->dev, "Error when init fxos8700 device:(%d)", result); @@ -652,14 +668,49 @@ static ssize_t fxos8700_position_store(struct device *dev, return count; } +static ssize_t fxos8700_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxos8700_data *pdata = g_fxos8700_data; + unsigned long range = atomic_read(&pdata->range); + + return sprintf(buf, "%ld\n", range); +} + +static ssize_t fxos8700_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long range; + struct fxos8700_data *pdata = g_fxos8700_data; + struct i2c_client *client = pdata->client; + int ret; + + if (kstrtoul(buf, 10, &range) < 0) + return -EINVAL; + + if (range == atomic_read(&pdata->range)) + return count; + + if (atomic_read(&pdata->acc_active) | atomic_read(&pdata->mag_active)) + printk(KERN_INFO "Pls set the sensor standby and then actived\n"); + ret = fxos8700_change_range(client, range); + if (!ret) + atomic_set(&pdata->range, range); + + return count; +} + static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxos8700_enable_show, fxos8700_enable_store); static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxos8700_poll_delay_show, fxos8700_poll_delay_store); static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxos8700_position_show, fxos8700_position_store); +static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, fxos8700_range_show, fxos8700_range_store); static struct attribute *fxos8700_attributes[] = { &dev_attr_enable.attr, &dev_attr_poll_delay.attr, &dev_attr_position.attr, + &dev_attr_range.attr, NULL }; From 93c9762c16036b2de83c73046959dcaa48c81a8e Mon Sep 17 00:00:00 2001 From: Gao Pan Date: Wed, 1 Jul 2015 14:38:20 +0800 Subject: [PATCH 0033/3047] =?UTF-8?q?MLK-11206:=20input:=20misc:=20fxls847?= =?UTF-8?q?1:=20support=20=C2=B12g/=C2=B14g/=C2=B18g=20dynamically=20selec?= =?UTF-8?q?tion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support ±2g/±4g/±8g dynamically selection for motion sensor fxls8471. Set the sensor mode to standby mode before changing the scale range with the command "echo 0 > enable". The scale range can be changed with the command "echo 0/1/2 > range". Signed-off-by: Gao Pan Signed-off-by: Fugang Duan (cherry picked from commit: 6824cff93d368eafbf96c71fad541f9bc2502e3a) --- drivers/input/misc/fxls8471.c | 51 +++++++++++++++++++++++++++++++++-- drivers/input/misc/fxls8471.h | 1 + 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/fxls8471.c b/drivers/input/misc/fxls8471.c index 95f027ebb0cf47..0b4b00503ee170 100644 --- a/drivers/input/misc/fxls8471.c +++ b/drivers/input/misc/fxls8471.c @@ -169,6 +169,15 @@ static int fxls8471_set_delay(struct fxls8471_data *pdata, int delay) return 0; } +static int fxls8471_change_range(struct fxls8471_data *pdata, int range) +{ + int ret; + + ret = fxls8471_bus_write(pdata, FXLS8471_XYZ_DATA_CFG, range); + + return ret; +} + static int fxls8471_read_data(struct fxls8471_data *pdata, struct fxls8471_data_axis *data) { @@ -319,7 +328,10 @@ static ssize_t fxls8471_enable_store(struct device *dev, ret = fxls8471_change_mode(pdata, (enable > 0 ? ACTIVED : STANDBY)); if (!ret) { atomic_set(&pdata->active, enable); - printk(KERN_INFO "mma enable setting active\n"); + if (enable) + printk(KERN_INFO "mma enable setting actived\n"); + else + printk(KERN_INFO "mma enable setting standby\n"); } return count; } @@ -386,8 +398,40 @@ static ssize_t fxls8471_data_show(struct device *dev, return sprintf(buf, "%d,%d,%d\n", data.x, data.y, data.z); } -static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxls8471_enable_show, fxls8471_enable_store); +static ssize_t fxls8471_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int range = 0; + + range = atomic_read(&pdata->range); + return sprintf(buf, "%d\n", range); +} +static ssize_t fxls8471_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fxls8471_data *pdata = &fxls8471_dev; + int ret; + unsigned long range; + + if (kstrtoul(buf, 10, &range) < 0) + return -EINVAL; + + if (range == atomic_read(&pdata->range)) + return count; + + if (atomic_read(&pdata->active)) + printk(KERN_INFO "Pls set the sensor standby and then actived\n"); + ret = fxls8471_change_range(pdata, range); + if (!ret) + atomic_set(&pdata->range, range); + + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxls8471_enable_show, fxls8471_enable_store); static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxls8471_poll_delay_show, fxls8471_poll_delay_store); @@ -396,11 +440,14 @@ static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxls8471_position_show, static DEVICE_ATTR(data, S_IWUSR | S_IRUGO, fxls8471_data_show, NULL); +static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, fxls8471_range_show, fxls8471_range_store); + static struct attribute *fxls8471_attributes[] = { &dev_attr_enable.attr, &dev_attr_poll_delay.attr, &dev_attr_position.attr, &dev_attr_data.attr, + &dev_attr_range.attr, NULL }; diff --git a/drivers/input/misc/fxls8471.h b/drivers/input/misc/fxls8471.h index adb0c31f892c93..6820ad1c05171b 100644 --- a/drivers/input/misc/fxls8471.h +++ b/drivers/input/misc/fxls8471.h @@ -80,6 +80,7 @@ struct fxls8471_data { atomic_t active; atomic_t delay; atomic_t position; + atomic_t range; u8 chip_id; }; From 80f3db955eacc4b804dbd2ef5e12959105629d31 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 27 Jul 2015 18:56:07 +0800 Subject: [PATCH 0034/3047] MLK-11290 ARM: dts: imx7d-12x12-lpddr3-arm2: add enet, i2c, max7322 support Add enet1, enet2, i2c1~4, max7322 support. Signed-off-by: Fugang Duan --- .../dts/imx7d-12x12-lpddr3-arm2-enet2.dts | 17 ++ arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts | 216 ++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2-enet2.dts diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2-enet2.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2-enet2.dts new file mode 100644 index 00000000000000..151853dc1712ad --- /dev/null +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2-enet2.dts @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "imx7d-12x12-lpddr3-arm2.dts" + +&epdc { + status = "disabled"; +}; + +&fec2 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts index 19cbc6a09f6913..f15c8da01d3cb5 100644 --- a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts @@ -41,11 +41,199 @@ }; }; +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, + <&clks IMX7D_ENET1_TIME_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <100000000>; + phy-mode = "rgmii"; + phy-handle = <ðphy1>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@5 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <5>; + }; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; +}; + +&fec2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet2>; + pinctrl-assert-gpios = <&max7322 0 GPIO_ACTIVE_HIGH>; + assigned-clocks = <&clks IMX7D_ENET2_TIME_ROOT_SRC>, + <&clks IMX7D_ENET2_TIME_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <100000000>; + phy-mode = "rgmii"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "disabled"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_1>; + status = "okay"; + + pmic: pfuze3000@08 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1850000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3_1>; + status = "okay"; + + max7322: gpio@68 { + compatible = "maxim,max7322"; + reg = <0x68>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog_1>; imx7d-12x12-lpddr3-arm2 { + pinctrl_enet1: enet1grp { + fsl,pins = < + MX7D_PAD_GPIO1_IO10__ENET1_MDIO 0x3 + MX7D_PAD_GPIO1_IO11__ENET1_MDC 0x3 + MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 + MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 + MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 + MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 + MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 + MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 + MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 + MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 + MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 + MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 + MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 + MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x1 + MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x1 + MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x1 + MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x1 + MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x1 + MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x1 + MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x1 + MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x1 + MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x1 + MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x1 + MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x1 + MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x1 + >; + }; + pinctrl_hog_1: hoggrp-1 { fsl,pins = < MX7D_PAD_I2C4_SCL__GPIO4_IO14 0x80000000 @@ -65,6 +253,34 @@ >; }; + pinctrl_i2c1_1: i2c1grp-1 { + fsl,pins = < + MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f + MX7D_PAD_I2C1_SCL__I2C1_SCL 0x4000007f + >; + }; + + pinctrl_i2c2_1: i2c2grp-1 { + fsl,pins = < + MX7D_PAD_I2C2_SDA__I2C2_SDA 0x4000007f + MX7D_PAD_I2C2_SCL__I2C2_SCL 0x4000007f + >; + }; + + pinctrl_i2c3_1: i2c3grp-1 { + fsl,pins = < + MX7D_PAD_I2C3_SDA__I2C3_SDA 0x4000007f + MX7D_PAD_I2C3_SCL__I2C3_SCL 0x4000007f + >; + }; + + pinctrl_i2c4_1: i2c4grp-1 { + fsl,pins = < + MX7D_PAD_I2C4_SDA__I2C4_SDA 0x4000007f + MX7D_PAD_I2C4_SCL__I2C4_SCL 0x4000007f + >; + }; + pinctrl_uart1_1: uart1grp-1 { fsl,pins = < MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 From 7607d5f296b88df504b6505df14311759a63963a Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 15 Oct 2014 09:36:40 +0800 Subject: [PATCH 0035/3047] MLK-9694 ARM: imx6: init enet MAC address Enet get MAC address order: From module parameters or kernel command line -> device tree -> pfuse -> mac registers set by bootloader -> random mac address. When there have no "fec.macaddr" parameters set in kernel command line, enet driver get MAC address from device tree. And then if the MAC address set in device tree and is valid, enet driver get MAC address from device tree. Otherwise,enet get MAarch/arm/mach-imx /mach-imx6q.cC address from pfuse. So, in the condition, update the MAC address (read from pfuse) to device tree. Cherry-pick & Merge patches from: 149ac988a25b8d8eb86d05679cbb7b42819ff7a1 & 3269e5c06bdb2f7ab9bd5afa9bbfe46d872197d3 Signed-off-by: Fugang Duan --- arch/arm/mach-imx/common.h | 1 + arch/arm/mach-imx/mach-imx6q.c | 90 +++++++++++++++++++++++++++++++-- arch/arm/mach-imx/mach-imx6sl.c | 11 ++-- arch/arm/mach-imx/mach-imx6sx.c | 1 + arch/arm/mach-imx/mach-imx7d.c | 1 + 5 files changed, 98 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index d971663a6114db..962eb48e89df6f 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -112,6 +112,7 @@ void imx_anatop_post_resume(void); int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); +void imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat); int imx_mmdc_get_ddr_type(void); int imx_ddrc_get_ddr_type(void); void imx_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 45801b27ee5ced..c63e6f6e3525ba 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -262,6 +263,91 @@ static void __init imx6q_axi_init(void) } } +#define OCOTP_MACn(n) (0x00000620 + (n) * 0x10) +void __init imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat) +{ + struct device_node *ocotp_np, *enet_np, *from = NULL; + void __iomem *base; + struct property *newmac; + u32 macaddr_low; + u32 macaddr_high = 0; + u32 macaddr1_high = 0; + u8 *macaddr; + int i; + + for (i = 0; i < 2; i++) { + enet_np = of_find_compatible_node(from, NULL, enet_compat); + if (!enet_np) + return; + + from = enet_np; + + if (of_get_mac_address(enet_np)) + goto put_enet_node; + + ocotp_np = of_find_compatible_node(NULL, NULL, ocotp_compat); + if (!ocotp_np) { + pr_warn("failed to find ocotp node\n"); + goto put_enet_node; + } + + base = of_iomap(ocotp_np, 0); + if (!base) { + pr_warn("failed to map ocotp\n"); + goto put_ocotp_node; + } + + macaddr_low = readl_relaxed(base + OCOTP_MACn(1)); + if (i) + macaddr1_high = readl_relaxed(base + OCOTP_MACn(2)); + else + macaddr_high = readl_relaxed(base + OCOTP_MACn(0)); + + newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); + if (!newmac) + goto put_ocotp_node; + + newmac->value = newmac + 1; + newmac->length = 6; + newmac->name = kstrdup("local-mac-address", GFP_KERNEL); + if (!newmac->name) { + kfree(newmac); + goto put_ocotp_node; + } + + macaddr = newmac->value; + if (i) { + macaddr[5] = (macaddr_low >> 16) & 0xff; + macaddr[4] = (macaddr_low >> 24) & 0xff; + macaddr[3] = macaddr1_high & 0xff; + macaddr[2] = (macaddr1_high >> 8) & 0xff; + macaddr[1] = (macaddr1_high >> 16) & 0xff; + macaddr[0] = (macaddr1_high >> 24) & 0xff; + } else { + macaddr[5] = macaddr_high & 0xff; + macaddr[4] = (macaddr_high >> 8) & 0xff; + macaddr[3] = (macaddr_high >> 16) & 0xff; + macaddr[2] = (macaddr_high >> 24) & 0xff; + macaddr[1] = macaddr_low & 0xff; + macaddr[0] = (macaddr_low >> 8) & 0xff; + } + + of_update_property(enet_np, newmac); + +put_ocotp_node: + of_node_put(ocotp_np); +put_enet_node: + of_node_put(enet_np); + } +} + +static inline void imx6q_enet_init(void) +{ + imx6_enet_mac_init("fsl,imx6q-fec", "fsl,imx6q-ocotp"); + imx6q_enet_phy_init(); + imx6q_1588_init(); +} + static void __init imx6q_init_machine(void) { struct device *parent; @@ -276,13 +362,11 @@ static void __init imx6q_init_machine(void) if (parent == NULL) pr_warn("failed to initialize soc device\n"); - imx6q_enet_phy_init(); - of_platform_default_populate(NULL, NULL, parent); + imx6q_enet_init(); imx_anatop_init(); cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); - imx6q_1588_init(); imx6q_axi_init(); } diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index 04084900d810b2..4ed2fb8bf6867e 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -19,7 +19,7 @@ #include "common.h" #include "cpuidle.h" -static void __init imx6sl_fec_init(void) +static void __init imx6sl_fec_clk_init(void) { struct regmap *gpr; @@ -30,9 +30,14 @@ static void __init imx6sl_fec_init(void) IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK, 0); regmap_update_bits(gpr, IOMUXC_GPR1, IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK, 0); - } else { + } else pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); - } +} + +static inline void imx6sl_fec_init(void) +{ + imx6sl_fec_clk_init(); + imx6_enet_mac_init("fsl,imx6sl-fec", "fsl,imx6sl-ocotp"); } static void __init imx6sl_init_late(void) diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index 7f52d9b1e8a451..bd264c461df2d3 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -60,6 +60,7 @@ static void __init imx6sx_enet_clk_sel(void) static inline void imx6sx_enet_init(void) { + imx6_enet_mac_init("fsl,imx6sx-fec", "fsl,imx6sx-ocotp"); imx6sx_enet_phy_init(); imx6sx_enet_clk_sel(); } diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 8b9b8cbfae3055..fd04c4a3eb2d2c 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -81,6 +81,7 @@ static void __init imx7d_enet_clk_sel(void) static inline void imx7d_enet_init(void) { + imx6_enet_mac_init("fsl,imx7d-fec", "fsl,imx7d-ocotp"); imx7d_enet_phy_init(); imx7d_enet_clk_sel(); } From bf9413feeb870b849ada79c5ee8de8d944de7891 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Thu, 25 Dec 2014 17:17:49 +0800 Subject: [PATCH 0036/3047] MLK-10060 ARM: i.MX6: disable ethernet phy AR8031 EEE mode in default Disable ethernet phy AR8031 EEE mode in default to reduce the IEEE1588 latency. Signed-off-by: Fugang Duan --- arch/arm/mach-imx/mach-imx6q.c | 8 ++++++++ arch/arm/mach-imx/mach-imx6sx.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index c63e6f6e3525ba..68e293490ec5c1 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -113,6 +113,14 @@ static int ar8031_phy_fixup(struct phy_device *dev) { u16 val; + /* disable phy AR8031 SmartEEE function. */ + phy_write(dev, 0xd, 0x3); + phy_write(dev, 0xe, 0x805d); + phy_write(dev, 0xd, 0x4003); + val = phy_read(dev, 0xe); + val &= ~(0x1 << 8); + phy_write(dev, 0xe, val); + /* To enable AR8031 output a 125MHz clk from CLK_25M */ phy_write(dev, 0xd, 0x7); phy_write(dev, 0xe, 0x8016); diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index bd264c461df2d3..fafd72b0654cb3 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -26,6 +26,14 @@ static int ar8031_phy_fixup(struct phy_device *dev) phy_write(dev, 0x1d, 0x1f); phy_write(dev, 0x1e, 0x8); + /* disable phy AR8031 SmartEEE function. */ + phy_write(dev, 0xd, 0x3); + phy_write(dev, 0xe, 0x805d); + phy_write(dev, 0xd, 0x4003); + val = phy_read(dev, 0xe); + val &= ~(0x1 << 8); + phy_write(dev, 0xe, val); + /* introduce tx clock delay */ phy_write(dev, 0x1d, 0x5); val = phy_read(dev, 0x1e); From a630b14e85ea79f9682b95b4e555138fea3c86e8 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 14 Jan 2015 16:18:58 +0800 Subject: [PATCH 0037/3047] MLK-10098 ARM: imx: fix 1588 clock init The enet clock define is changed as there has no "enet_ref" clock name. If the tx_clk is sourced from SOC anatop PLL, user define the clock id in devicetree. So we only to judge the ptp clock valid and then set the related GPR bit. Signed-off-by: Fugang Duan (cherry picked from commit: 01ed2a839d9b76ccb4113dc2a04af4a33b33de22) --- arch/arm/mach-imx/mach-imx6q.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 68e293490ec5c1..cbdee5106bf49d 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -193,9 +193,7 @@ static void __init imx6q_1588_init(void) { struct device_node *np; struct clk *ptp_clk; - struct clk *enet_ref; struct regmap *gpr; - u32 clksel; np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec"); if (!np) { @@ -209,30 +207,19 @@ static void __init imx6q_1588_init(void) goto put_node; } - enet_ref = clk_get_sys(NULL, "enet_ref"); - if (IS_ERR(enet_ref)) { - pr_warn("%s: failed to get enet clock\n", __func__); - goto put_ptp_clk; - } - /* * If enet_ref from ANATOP/CCM is the PTP clock source, we need to * set bit IOMUXC_GPR1[21]. Or the PTP clock must be from pad * (external OSC), and we need to clear the bit. */ - clksel = clk_is_match(ptp_clk, enet_ref) ? - IMX6Q_GPR1_ENET_CLK_SEL_ANATOP : - IMX6Q_GPR1_ENET_CLK_SEL_PAD; gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); if (!IS_ERR(gpr)) regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_ENET_CLK_SEL_MASK, - clksel); + IMX6Q_GPR1_ENET_CLK_SEL_ANATOP); else pr_err("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); - clk_put(enet_ref); -put_ptp_clk: clk_put(ptp_clk); put_node: of_node_put(np); From 865a01e3ba77533658346fbfb0a7c8171bcdb516 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 6 Feb 2015 16:42:46 +0800 Subject: [PATCH 0038/3047] MLK-10463-1 ARM: imx: init ENET RGMII tx clock source Init ENET RGMII tx clock source, set GPR5[9] to select clock from internal PLL_enet. And set phy VDDIO to 1.8V that get better signal quality. Signed-off-by: Fugang Duan (cherry picked from commit: d7a171fcf5218166f558428610ca8e9cb9f7e830) --- arch/arm/mach-imx/mach-imx6q.c | 18 ++++++++++++++++++ include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 + 2 files changed, 19 insertions(+) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index cbdee5106bf49d..2a549698faa2d1 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -113,6 +113,10 @@ static int ar8031_phy_fixup(struct phy_device *dev) { u16 val; + /* Set RGMII IO voltage to 1.8V */ + phy_write(dev, 0x1d, 0x1f); + phy_write(dev, 0x1e, 0x8); + /* disable phy AR8031 SmartEEE function. */ phy_write(dev, 0xd, 0x3); phy_write(dev, 0xe, 0x805d); @@ -258,6 +262,18 @@ static void __init imx6q_axi_init(void) } } +static void __init imx6q_enet_clk_sel(void) +{ + struct regmap *gpr; + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR5, + IMX6Q_GPR5_ENET_TX_CLK_SEL, IMX6Q_GPR5_ENET_TX_CLK_SEL); + else + pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); +} + #define OCOTP_MACn(n) (0x00000620 + (n) * 0x10) void __init imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat) { @@ -341,6 +357,8 @@ static inline void imx6q_enet_init(void) imx6_enet_mac_init("fsl,imx6q-fec", "fsl,imx6q-ocotp"); imx6q_enet_phy_init(); imx6q_1588_init(); + if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0) + imx6q_enet_clk_sel(); } static void __init imx6q_init_machine(void) diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index c8e0164c54236f..57be5496a08c83 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -243,6 +243,7 @@ #define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0) #define IMX6Q_GPR5_L2_CLK_STOP BIT(8) +#define IMX6Q_GPR5_ENET_TX_CLK_SEL BIT(9) #define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0) #define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4) From da8d7cd502c89c2225698dc6909cff62c013867b Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 28 Jul 2015 11:09:20 +0800 Subject: [PATCH 0039/3047] MLK-10447-01: dts: imx7d sdb: Add 74LV595 driver -74LV595 function compatible with 74HC595, add 74HC595 driver into imx7d sdb dts. -74LV595 register as a GPIO device and access 74LV595 chip by SPI GPIO, so add spi_gpio driver into imx7 sdb dts. Signed-off-by: Sandor Yu igned-off-by: Fugang Duan (cherry picked from commit: 61fe7af7e47dd8bf6acc91ceabd9e660d28de28a) --- arch/arm/boot/dts/imx7d-sdb.dts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 340f81656268ea..43c264d27110e5 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -94,6 +94,29 @@ regulator-max-microvolt = <1800000>; }; }; + + spi4 { + compatible = "spi-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1>; + status = "okay"; + gpio-sck = <&gpio1 13 0>; + gpio-mosi = <&gpio1 9 0>; + cs-gpios = <&gpio1 12 0>; + num-chipselects = <1>; + #address-cells = <1>; + #size-cells = <0>; + + gpio_spi: gpio_spi@0 { + compatible = "fairchild,74hc595"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + registers-number = <1>; + registers-default = /bits/ 8 <0x74>; /* Enable PERI_3V3, SENSOR_RST_B and HDMI_RST*/ + spi-max-frequency = <100000>; + }; + }; }; &adc1 { @@ -139,6 +162,7 @@ &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet1>; + pinctrl-assert-gpios = <&gpio_spi 5 GPIO_ACTIVE_HIGH>; assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, <&clks IMX7D_ENET1_TIME_ROOT_CLK>; assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; @@ -520,6 +544,14 @@ >; }; + pinctrl_spi1: spi1grp { + fsl,pins = < + MX7D_PAD_GPIO1_IO09__GPIO1_IO9 0x59 + MX7D_PAD_GPIO1_IO12__GPIO1_IO12 0x59 + MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x59 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 From 9074c2327efa06dc707fbd75113e07d6d5464b19 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 28 Jul 2015 11:13:20 +0800 Subject: [PATCH 0040/3047] MLK-10447-03: ARM: imx_v7_defconfig: Add spi gpio and gpio 74x164 Enable CONFIG_SPI_GPIO and CONFIG_GPIO_74X164 to imx_v7_defconfig. Signed-off-by: Sandor Yu Signed-off-by: Fugang Duan (cherry picked from commit: a551a35455d14d265ce7aeb4a0e6081303f43fec) --- arch/arm/configs/imx_v7_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 3d8aa95897ac5c..0933afae79f050 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -178,10 +178,12 @@ CONFIG_I2C_ALGOPCF=m CONFIG_I2C_ALGOPCA=m CONFIG_I2C_IMX=y CONFIG_SPI=y +CONFIG_SPI_GPIO=y CONFIG_SPI_IMX=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_MAX732X=y CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_74X164=y CONFIG_POWER_SUPPLY=y CONFIG_SENSORS_MAG3110=y CONFIG_THERMAL=y From 5fd7a12318e42994ce25500667680680ed8e63fa Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 14 Jul 2013 21:52:38 +0800 Subject: [PATCH 0041/3047] MLK-11293: gpio: pca953x: add device_reset() call The pca953x type of devices, e.g. max7310, may have a reset which needs to be handled to get the device start working. Add a device_reset() call for that, and defer the probe if the reset controller for that is not ready yet. Signed-off-by: Shawn Guo Signed-off-by: Fugang Duan (cherry picked from commit: d3264091b30b777d94a18efda9823a06668d5b10) --- drivers/gpio/gpio-pca953x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index fe731f09425712..f0bb7b5aabb689 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -813,6 +814,10 @@ static int pca953x_probe(struct i2c_client *client, lockdep_set_subclass(&chip->i2c_lock, i2c_adapter_depth(client->adapter)); + ret = device_reset(&client->dev); + if (ret == -ENODEV) + return -EPROBE_DEFER; + /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ From 3ae9ce06c97270f17b15f804006c77c2a1f28b41 Mon Sep 17 00:00:00 2001 From: Sandor Yu Date: Fri, 20 Mar 2015 14:58:20 +0800 Subject: [PATCH 0042/3047] MLK-10449-1: 74x164: Add new property registers-default For some platform such as imx7D SDB, one pin of 74x164 to control all peripheral power supply(PERI_3V_EN). The pin should keep in high voltage level when 74x164 loading, otherwise the module depend on PERI_3V3 will lose power. So add new property registers-default into 74x164 driver. Signed-off-by: Sandor Yu Signed-off-by: Fugang Duan (cherry picked from commit: 61fe7af7e47dd8bf6acc91ceabd9e660d28de28a) --- drivers/gpio/gpio-74x164.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index a6607faf2fdf82..fbca09c926868f 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -138,6 +138,9 @@ static int gen_74x164_probe(struct spi_device *spi) chip->registers = nregs; chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; + of_property_read_u8_array(spi->dev.of_node, "registers-default", + chip->buffer, chip->registers); + chip->gpio_chip.can_sleep = true; chip->gpio_chip.parent = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; From fbdb3f1cd467491d2b8d24593d8ca769e5d86830 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Thu, 30 Jul 2015 22:22:26 +0800 Subject: [PATCH 0043/3047] MLK-11300-01 ARM: dts: imx: add imx6ul dtsi support. Add i.MX6UL SOC dtsi file. Signed-off-by: Anson Huang Signed-off-by: Bai Ping [Octavian: merge 4.1.y into upstream keeping upstream values where values are different] Signed-off-by: Octavian Purdila --- arch/arm/boot/dts/imx6ul.dtsi | 259 ++++++++++++++++++++++++++++++++-- 1 file changed, 251 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi index c5c05fdccc783d..3da5fade416086 100644 --- a/arch/arm/boot/dts/imx6ul.dtsi +++ b/arch/arm/boot/dts/imx6ul.dtsi @@ -133,6 +133,24 @@ interrupt-parent = <&gpc>; ranges; + busfreq { + compatible = "fsl,imx_busfreq"; + clocks = <&clks IMX6UL_CLK_PLL2_PFD2>, <&clks IMX6UL_CLK_PLL2_198M>, + <&clks IMX6UL_CLK_PLL2_BUS>, <&clks IMX6UL_CLK_ARM>, + <&clks IMX6UL_CLK_PLL3_USB_OTG>, <&clks IMX6UL_CLK_PERIPH>, + <&clks IMX6UL_CLK_PERIPH_PRE>, <&clks IMX6UL_CLK_PERIPH_CLK2>, + <&clks IMX6UL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6UL_CLK_OSC>, + <&clks IMX6UL_CLK_AHB>, <&clks IMX6UL_CLK_AXI>, + <&clks IMX6UL_CLK_PERIPH2>, <&clks IMX6UL_CLK_PERIPH2_PRE>, + <&clks IMX6UL_CLK_PERIPH2_CLK2>, <&clks IMX6UL_CLK_PERIPH2_CLK2_SEL>, + <&clks IMX6UL_CLK_STEP>, <&clks IMX6UL_CLK_MMDC_P0_FAST>; + clock-names = "pll2_pfd2_396m", "pll2_198m", "pll2_bus", "arm", "pll3_usb_otg", + "periph", "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", + "ahb", "ocram", "periph2", "periph2_pre", "periph2_clk2", "periph2_clk2_sel", + "step", "mmdc"; + fsl,max_ddr_freq = <400000000>; + }; + pmu { compatible = "arm,cortex-a7-pmu"; interrupts = ; @@ -157,6 +175,17 @@ clocks = <&clks IMX6UL_CLK_APBHDMA>; }; + caam_sm: caam-sm@00100000 { + compatible = "fsl,imx7d-caam-sm", "fsl,imx6q-caam-sm"; + reg = <0x00100000 0x3fff>; + }; + + irq_sec_vio: caam_secvio { + compatible = "fsl,imx7d-caam-secvio", "fsl,imx6q-caam-secvio"; + interrupts = ; + }; + + gpmi: gpmi-nand@01806000 { compatible = "fsl,imx6q-gpmi-nand"; #address-cells = <1>; @@ -191,6 +220,28 @@ reg = <0x02000000 0x40000>; ranges; + spdif: spdif@02004000 { + compatible = "fsl,imx6ul-spdif", "fsl,imx35-spdif"; + reg = <0x02004000 0x4000>; + interrupts = ; + dmas = <&sdma 41 18 0>, + <&sdma 42 18 0>; + dma-names = "rx", "tx"; + clocks = <&clks IMX6UL_CLK_SPDIF_GCLK>, + <&clks IMX6UL_CLK_OSC>, + <&clks IMX6UL_CLK_SPDIF>, + <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_DUMMY>, + <&clks IMX6UL_CLK_IPG>, + <&clks IMX6UL_CLK_DUMMY>, <&clks IMX6UL_CLK_DUMMY>, + <&clks IMX6UL_CLK_SPBA>; + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", + "rxtx7", "dma"; + status = "disabled"; + }; + ecspi1: ecspi@02008000 { #address-cells = <1>; #size-cells = <0>; @@ -200,6 +251,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI1>, <&clks IMX6UL_CLK_ECSPI1>; clock-names = "ipg", "per"; + dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -212,6 +265,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI2>, <&clks IMX6UL_CLK_ECSPI2>; clock-names = "ipg", "per"; + dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -224,6 +279,8 @@ clocks = <&clks IMX6UL_CLK_ECSPI3>, <&clks IMX6UL_CLK_ECSPI3>; clock-names = "ipg", "per"; + dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -236,23 +293,27 @@ clocks = <&clks IMX6UL_CLK_ECSPI4>, <&clks IMX6UL_CLK_ECSPI4>; clock-names = "ipg", "per"; + dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; + dma-names = "rx", "tx"; status = "disabled"; }; uart7: serial@02018000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02018000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART7_IPG>, <&clks IMX6UL_CLK_UART7_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 43 4 0>, <&sdma 44 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; uart1: serial@02020000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02020000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART1_IPG>, @@ -263,12 +324,14 @@ uart8: serial@02024000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02024000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART8_IPG>, <&clks IMX6UL_CLK_UART8_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 45 4 0>, <&sdma 46 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -316,6 +379,31 @@ dma-names = "rx", "tx"; status = "disabled"; }; + + asrc: asrc@02034000 { + compatible = "fsl,imx53-asrc"; + reg = <0x02034000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_ASRC_IPG>, + <&clks IMX6UL_CLK_ASRC_MEM>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks IMX6UL_CLK_SPDIF>, <&clks 0>, <&clks 0>, + <&clks IMX6UL_CLK_SPBA>; + clock-names = "mem", "ipg", "asrck_0", + "asrck_1", "asrck_2", "asrck_3", "asrck_4", + "asrck_5", "asrck_6", "asrck_7", "asrck_8", + "asrck_9", "asrck_a", "asrck_b", "asrck_c", + "asrck_d", "asrck_e", "asrck_f", "dma"; + dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, + <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; + dma-names = "rxa", "rxb", "rxc", + "txa", "txb", "txc"; + fsl,asrc-rate = <48000>; + fsl,asrc-width = <16>; + status = "okay"; + }; }; tsc: tsc@02040000 { @@ -329,6 +417,19 @@ status = "disabled"; }; + touchctrl: touchctrl@02040000 { + compatible = "fsl,imx6ul-touchctrl"; + reg = <0x02040000 0x4000>; + status = "disabled"; + }; + + bee: bee@02044000 { + compatible = "fsl,imx6ul-bee"; + reg = <0x02044000 0x4000>; + interrupts = ; + status = "disabled"; + }; + pwm1: pwm@02080000 { compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm"; reg = <0x02080000 0x4000>; @@ -390,6 +491,7 @@ clocks = <&clks IMX6UL_CLK_CAN2_IPG>, <&clks IMX6UL_CLK_CAN2_SERIAL>; clock-names = "ipg", "per"; + stop-mode = <&gpr 0x10 2 0x10 18>; status = "disabled"; }; @@ -463,6 +565,12 @@ gpio-ranges = <&iomuxc 0 7 10>, <&iomuxc 10 5 2>; }; + snvslp: snvs@020b0000 { + compatible = "fsl,imx6ul-snvs"; + reg = <0x020b0000 0x4000>; + interrupts = ; + }; + fec2: ethernet@020b4000 { compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec"; reg = <0x020b4000 0x4000>; @@ -475,8 +583,11 @@ <&clks IMX6UL_CLK_ENET2_REF_125M>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; + stop-mode = <&gpr 0x10 4>; fsl,num-tx-queues=<1>; fsl,num-rx-queues=<1>; + fsl,magic-packet; + fsl,wakeup_irq = <0>; status = "disabled"; }; @@ -588,6 +699,19 @@ fsl,anatop = <&anatop>; }; + tempmon: tempmon { + compatible = "fsl,imx6ul-tempmon", "fsl,imx6sx-tempmon"; + interrupts = ; + fsl,tempmon = <&anatop>; + fsl,tempmon-data = <&ocotp>; + clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>; + }; + + caam_snvs: caam-snvs@020cc000 { + compatible = "fsl,imx6q-caam-snvs"; + reg = <0x020cc000 0x4000>; + }; + snvs: snvs@020cc000 { compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; reg = <0x020cc000 0x4000>; @@ -642,6 +766,7 @@ #interrupt-cells = <3>; interrupts = ; interrupt-parent = <&intc>; + fsl,mf-mix-wakeup-irq = <0x7c00000 0x7d00 0x0 0x1400640>; }; iomuxc: iomuxc@020e0000 { @@ -664,6 +789,13 @@ clock-names = "ipg", "per"; }; + mqs: mqs { + compatible = "fsl,imx6sx-mqs"; + gpr = <&gpr>; + status = "disabled"; + }; + + sdma: sdma@020ec000 { compatible = "fsl,imx6ul-sdma", "fsl,imx6q-sdma", "fsl,imx35-sdma"; @@ -673,6 +805,7 @@ <&clks IMX6UL_CLK_SDMA>; clock-names = "ipg", "ahb"; #dma-cells = <3>; + iram = <&ocram>; fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; }; @@ -728,6 +861,35 @@ reg = <0x02100000 0x100000>; ranges; + crypto: caam@2140000 { + compatible = "fsl,imx6ul-caam", "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2140000 0x3c000>; + ranges = <0 0x2140000 0x3c000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_CAAM_IPG>, <&clks IMX6UL_CLK_CAAM_ACLK>, + <&clks IMX6UL_CLK_CAAM_MEM>; + clock-names = "caam_ipg", "caam_aclk", "caam_mem"; + + sec_jr0: jr0@1000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupts = ; + }; + + sec_jr1: jr1@2000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupts = ; + }; + sec_jr2: jr2@3000 { + compatible = "fsl,sec-v4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupts = ; + }; + }; + usbotg1: usb@02184000 { compatible = "fsl,imx6ul-usb", "fsl,imx27-usb"; reg = <0x02184000 0x200>; @@ -773,8 +935,18 @@ <&clks IMX6UL_CLK_ENET_REF>; clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out"; + stop-mode = <&gpr 0x10 3>; fsl,num-tx-queues=<1>; fsl,num-rx-queues=<1>; + fsl,magic-packet; + fsl,wakeup_irq = <0>; + status = "disabled"; + }; + + sim1: sim@0218c000 { + compatible = "fsl,imx6ul-sim"; + reg = <0x0218c000 0x4000>; + interrupts = ; status = "disabled"; }; @@ -844,11 +1016,62 @@ status = "disabled"; }; + romcp@021ac000 { + compatible = "fsl,imx6ul-romcp", "syscon"; + reg = <0x021ac000 0x4000>; + }; + mmdc: mmdc@021b0000 { compatible = "fsl,imx6ul-mmdc", "fsl,imx6q-mmdc"; reg = <0x021b0000 0x4000>; }; + sim2: sim@021b4000 { + compatible = "fsl,imx6ul-sim"; + reg = <0x021b4000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_SIM2>; + clock-names = "sim"; + status = "disabled"; + }; + + weim: weim@021b8000 { + compatible = "fsl,imx6ul-weim", "fsl,imx6q-weim"; + reg = <0x021b8000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_DUMMY>; + }; + + ocotp: ocotp-ctrl@021bc000 { + compatible = "syscon"; + reg = <0x021bc000 0x4000>; + clocks = <&clks IMX6UL_CLK_OCOTP>; + }; + + ocotp-fuse@021bc000 { + compatible = "fsl,imx6ul-ocotp", "fsl,imx6q-ocotp"; + reg = <0x021bc000 0x4000>; + clocks = <&clks IMX6UL_CLK_OCOTP>; + }; + + csu: csu@021c0000 { + compatible = "fsl,imx6ul-csu"; + reg = <0x021c0000 0x4000>; + interrupts = ; + status = "disabled"; + }; + + csi: csi@021c4000 { + compatible = "fsl,imx6ul-csi", "fsl,imx6s-csi"; + reg = <0x021c4000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_DUMMY>, + <&clks IMX6UL_CLK_CSI>, + <&clks IMX6UL_CLK_DUMMY>; + clock-names = "disp-axi", "csi_mclk", "disp_dcic"; + status = "disabled"; + }; + lcdif: lcdif@021c8000 { compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif"; reg = <0x021c8000 0x4000>; @@ -873,47 +1096,65 @@ status = "disabled"; }; + pxp: pxp@021cc000 { + compatible = "fsl,imx6ul-pxp-dma", "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; + reg = <0x021cc000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_PXP>, + <&clks IMX6UL_CLK_DUMMY>; + clock-names = "pxp-axi", "disp-axi"; + status = "disabled"; + }; + uart2: serial@021e8000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021e8000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART2_IPG>, <&clks IMX6UL_CLK_UART2_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; uart3: serial@021ec000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021ec000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART3_IPG>, <&clks IMX6UL_CLK_UART3_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; uart4: serial@021f0000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f0000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART4_IPG>, <&clks IMX6UL_CLK_UART4_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; uart5: serial@021f4000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f4000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART5_IPG>, <&clks IMX6UL_CLK_UART5_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -929,12 +1170,14 @@ uart6: serial@021fc000 { compatible = "fsl,imx6ul-uart", - "fsl,imx6q-uart"; + "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021fc000 0x4000>; interrupts = ; clocks = <&clks IMX6UL_CLK_UART6_IPG>, <&clks IMX6UL_CLK_UART6_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 0 4 0>, <&sdma 47 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; }; From 4f3f4768f7366c2a70537e12969eb2d994343bd6 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Thu, 30 Jul 2015 01:33:13 +0800 Subject: [PATCH 0044/3047] MLK-11300-02 ARM: dts: imx: add imx6ul board dts support Add i.MX6UL board support dts file for boards: * imx6ul-14X14-evk.dts * imx6ul-14x14-ddr3-arm2.dts Signed-off-by: Ye.Li Signed-off-by: Bai Ping [Octavian: merge with upstream, prefer upstrem in case of conflict] Signed-off-by: Octavian Purdila --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/imx6ul-14x14-ddr3-arm2.dts | 747 +++++++++++++++++++ arch/arm/boot/dts/imx6ul-14x14-evk.dts | 178 +++++ 3 files changed, 927 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/imx6ul-14x14-ddr3-arm2.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b254b26aa19849..d76ba18c9d75a0 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -423,7 +423,8 @@ dtb-$(CONFIG_SOC_IMX6UL) += \ imx6ul-pico-hobbit.dtb \ imx6ul-tx6ul-0010.dtb \ imx6ul-tx6ul-0011.dtb \ - imx6ul-tx6ul-mainboard.dtb + imx6ul-tx6ul-mainboard.dtb \ + imx6ul-14x14-ddr3-arm2.dtb dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-cl-som-imx7.dtb \ imx7d-colibri-eval-v3.dtb \ diff --git a/arch/arm/boot/dts/imx6ul-14x14-ddr3-arm2.dts b/arch/arm/boot/dts/imx6ul-14x14-ddr3-arm2.dts new file mode 100644 index 00000000000000..dbcc01792e69dd --- /dev/null +++ b/arch/arm/boot/dts/imx6ul-14x14-ddr3-arm2.dts @@ -0,0 +1,747 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/dts-v1/; + +#include +#include "imx6ul.dtsi" + +/ { + model = "Freescale i.MX6 UltraLite DDR3 ARM2 Board"; + compatible = "fsl,imx6ul-14x14-ddr3-arm2", "fsl,imx6ul"; + + chosen { + stdout-path = &uart1; + }; + + memory { + reg = <0x80000000 0x40000000>; + }; + + pxp_v4l2 { + compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + reg_sd1_vmmc: sd1_vmmc { + compatible = "regulator-fixed"; + regulator-name = "SD1_SPWR"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_sd2_vmmc: sd2_vmmc { + compatible = "regulator-fixed"; + regulator-name = "SD2_SPWR"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio4 10 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_can2_3v3: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "can2-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 15 GPIO_ACTIVE_LOW>; + }; + + reg_vref_3v3: regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "vref-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_usb_otg1_vbus: regulator@2 { + compatible = "regulator-fixed"; + reg = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_otg1>; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + }; +}; + +&cpu0 { + /* + * on i.MX6UL, no seperated VDD_ARM_IN and VDD_SOC_IN, + * to align with other platform and use the same cpufreq + * driver, still use the seperated OPP define for arm + * and soc. + */ + operating-points = < + /* kHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + fsl,soc-operating-points = < + /* KHz uV */ + 528000 1175000 + 396000 1175000 + 198000 1175000 + >; + arm-supply = <&sw1a_reg>; + soc-supply = <&sw1a_reg>; + fsl,arm-soc-shared = <1>; +}; + +&ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 26 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1_1 &pinctrl_ecspi1_cs_1>; + status = "okay"; + + flash: n25q032@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,n25q032"; + spi-max-frequency = <20000000>; + reg = <0>; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + phy-mode = "rmii"; + phy-handle = <ðphy0>; + status = "okay"; +}; + +&fec2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet2>; + phy-mode = "mii"; + phy-handle = <ðphy1>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + + ethphy1: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + }; + }; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can2_3v3>; + status = "disabled"; +}; + +&gpc { + fsl,cpu_pupscr_sw2iso = <0x1>; + fsl,cpu_pupscr_sw = <0x0>; + fsl,cpu_pdnscr_iso2sw = <0x1>; + fsl,cpu_pdnscr_iso = <0x1>; + fsl,wdog-reset = <1>; /* watchdog select of reset source */ + fsl,ldo-bypass = <1>; /* use ldo-bypass, u-boot will check it and configure */ +}; + +&gpmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpmi_nand_1>; + status = "disabled"; + nand-on-flash-bbt; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: pfuze100@08 { + compatible = "fsl,pfuze200"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog &pinctrl_hog1 &pinctrl_hog_sd>; + + imx6ul-ddr3-arm2 { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */ + MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x17059 /* SD1 WP */ + MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */ + MX6UL_PAD_CSI_MCLK__GPIO4_IO17 0x17059 /* SD2 CD */ + MX6UL_PAD_CSI_PIXCLK__GPIO4_IO18 0x17059 /* SD2 WP */ + >; + }; + + pinctrl_hog1: hoggrp1 { + fsl,pins = < + MX6UL_PAD_NAND_ALE__GPIO4_IO10 0x17059 /* SD2 RESECT */ + >; + }; + + pinctrl_hog_sd: hoggrp_sd { + fsl,pins = < + MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */ + MX6UL_PAD_GPIO1_IO08__USDHC2_VSELECT 0x17059 /* SD2 VSELECT */ + >; + }; + + pinctrl_adc1: adc1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0xb0 + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 + >; + }; + + pinctrl_bt: btgrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x80000000 + MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x80000000 + MX6UL_PAD_SNVS_TAMPER5__GPIO5_IO05 0x80000000 + >; + }; + + pinctrl_ecspi1_cs_1: ecspi1_cs_grp-1 { + fsl,pins = < + MX6UL_PAD_CSI_DATA05__GPIO4_IO26 0x10b0 + >; + }; + + pinctrl_ecspi1_1: ecspi1grp-1 { + fsl,pins = < + MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI 0x10b0 + MX6UL_PAD_CSI_DATA07__ECSPI1_MISO 0x10b0 + MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK 0x10b0 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 + MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b0a8 + >; + }; + + pinctrl_enet2: enet2grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0 + MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0 + MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0 + MX6UL_PAD_UART4_TX_DATA__ENET2_TDATA02 0x1b0b0 + MX6UL_PAD_UART4_RX_DATA__ENET2_TDATA03 0x1b0b0 + MX6UL_PAD_ENET2_TX_CLK__ENET2_TX_CLK 0x4001b0a8 + MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0 + MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0 + MX6UL_PAD_UART3_TX_DATA__ENET2_RDATA02 0x1b0b0 + MX6UL_PAD_UART3_RX_DATA__ENET2_RDATA03 0x1b0b0 + MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0 + MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0 + MX6UL_PAD_UART3_CTS_B__ENET2_RX_CLK 0x4001b0a8 + MX6UL_PAD_UART5_RX_DATA__ENET2_COL 0x1b0b0 + MX6UL_PAD_UART5_TX_DATA__ENET2_CRS 0x1b0b0 + >; + }; + + pinctrl_flexcan2: flexcan2grp{ + fsl,pins = < + MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020 + MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020 + MX6UL_PAD_JTAG_TRST_B__GPIO1_IO15 0x17059 /* STBY */ + >; + }; + + pinctrl_gpmi_nand_1: gpmi-nand-1 { + fsl,pins = < + MX6UL_PAD_NAND_CLE__RAWNAND_CLE 0xb0b1 + MX6UL_PAD_NAND_ALE__RAWNAND_ALE 0xb0b1 + MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B 0xb0b1 + MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000 + MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B 0xb0b1 + MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B 0xb0b1 + MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B 0xb0b1 + MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B 0xb0b1 + MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00 0xb0b1 + MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01 0xb0b1 + MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02 0xb0b1 + MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03 0xb0b1 + MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04 0xb0b1 + MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05 0xb0b1 + MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06 0xb0b1 + MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07 0xb0b1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO03__I2C1_SDA 0x4001b8b1 + MX6UL_PAD_GPIO1_IO02__I2C1_SCL 0x4001b8b1 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__I2C4_SCL 0x4001b8b0 + MX6UL_PAD_UART2_RX_DATA__I2C4_SDA 0x4001b8b0 + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 + MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 + MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 + MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 + MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 + MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 + MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 + MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 + MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 + MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 + MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 + MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 + MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 + MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 + MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 + MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 + MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 + MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 + MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79 + MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79 + MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79 + MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79 + MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79 + MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79 + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 + MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 + MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 + MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 + MX6UL_PAD_LCD_RESET__LCDIF_RESET 0x79 + >; + }; + + pinctrl_mqs: mqsgrp { + fsl,pins = < + MX6UL_PAD_JTAG_TDI__MQS_LEFT 0x11088 + MX6UL_PAD_JTAG_TDO__MQS_RIGHT 0x11088 + >; + }; + + pinctrl_pwm1: pmw1grp { + fsl,pins = < + MX6UL_PAD_ENET1_RX_DATA0__PWM1_OUT 0x110b0 + >; + }; + + pinctrl_qspi: qspigrp { + fsl,pins = < + MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK 0x70a1 + MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00 0x70a1 + MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01 0x70a1 + MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02 0x70a1 + MX6UL_PAD_NAND_CLE__QSPI_A_DATA03 0x70a1 + MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B 0x70a1 + MX6UL_PAD_NAND_DATA07__QSPI_A_SS1_B 0x70a1 + MX6UL_PAD_NAND_RE_B__QSPI_B_SCLK 0x70a1 + MX6UL_PAD_NAND_DATA02__QSPI_B_DATA00 0x70a1 + MX6UL_PAD_NAND_DATA03__QSPI_B_DATA01 0x70a1 + MX6UL_PAD_NAND_DATA04__QSPI_B_DATA02 0x70a1 + MX6UL_PAD_NAND_DATA05__QSPI_B_DATA03 0x70a1 + MX6UL_PAD_NAND_WE_B__QSPI_B_SS0_B 0x70a1 + MX6UL_PAD_NAND_DATA00__QSPI_B_SS1_B 0x70a1 + >; + }; + + pinctrl_sai2: sai2grp { + fsl,pins = < + MX6UL_PAD_SD1_DATA0__SAI2_TX_SYNC 0x1b0b0 + MX6UL_PAD_SD1_DATA1__SAI2_TX_BCLK 0x1b0b0 + MX6UL_PAD_SD1_DATA2__SAI2_RX_DATA 0x110b0 + MX6UL_PAD_SD1_DATA3__SAI2_TX_DATA 0x1f0b8 + MX6UL_PAD_SD1_CLK__SAI2_MCLK 0x1b0b0 + MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x17059 + >; + }; + + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO08__SPDIF_OUT 0x1b0b0 + MX6UL_PAD_GPIO1_IO09__SPDIF_IN 0x1b0b0 + >; + }; + + pinctrl_tsc: tscgrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 + MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0 + MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0 + MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 + MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1 + MX6UL_PAD_UART2_CTS_B__UART2_DCE_CTS 0x1b0b1 + MX6UL_PAD_UART2_RTS_B__UART2_DCE_RTS 0x1b0b1 + >; + }; + + pinctrl_uart2dte: uart2dtegrp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX 0x1b0b1 + MX6UL_PAD_UART2_CTS_B__UART2_DTE_RTS 0x1b0b1 + MX6UL_PAD_UART2_RTS_B__UART2_DTE_CTS 0x1b0b1 + >; + }; + + pinctrl_usb_otg1_id: usbotg1idgrp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x17059 + >; + }; + + pinctrl_usb_otg1: usbotg1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x10b0 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc1_8bit: usdhc1_8bit_grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10059 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + MX6UL_PAD_NAND_READY_B__USDHC1_DATA4 0x17059 + MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5 0x17059 + MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6 0x17059 + MX6UL_PAD_NAND_CLE__USDHC1_DATA7 0x17059 + >; + }; + + pinctrl_usdhc1_8bit_100mhz: usdhc1_8bit_100mhz_grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9 + MX6UL_PAD_NAND_READY_B__USDHC1_DATA4 0x170b9 + MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5 0x170b9 + MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6 0x170b9 + MX6UL_PAD_NAND_CLE__USDHC1_DATA7 0x170b9 + >; + }; + + pinctrl_usdhc1_8bit_200mhz: usdhc1_8bit_200mhz_grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9 + MX6UL_PAD_NAND_READY_B__USDHC1_DATA4 0x170f9 + MX6UL_PAD_NAND_CE0_B__USDHC1_DATA5 0x170f9 + MX6UL_PAD_NAND_CE1_B__USDHC1_DATA6 0x170f9 + MX6UL_PAD_NAND_CLE__USDHC1_DATA7 0x170f9 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6UL_PAD_CSI_HSYNC__USDHC2_CMD 0x17059 + MX6UL_PAD_CSI_VSYNC__USDHC2_CLK 0x10059 + MX6UL_PAD_CSI_DATA00__USDHC2_DATA0 0x17059 + MX6UL_PAD_CSI_DATA01__USDHC2_DATA1 0x17059 + MX6UL_PAD_CSI_DATA02__USDHC2_DATA2 0x17059 + MX6UL_PAD_CSI_DATA03__USDHC2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2grp100mhz { + fsl,pins = < + MX6UL_PAD_CSI_HSYNC__USDHC2_CMD 0x170b9 + MX6UL_PAD_CSI_VSYNC__USDHC2_CLK 0x100b9 + MX6UL_PAD_CSI_DATA00__USDHC2_DATA0 0x170b9 + MX6UL_PAD_CSI_DATA01__USDHC2_DATA1 0x170b9 + MX6UL_PAD_CSI_DATA02__USDHC2_DATA2 0x170b9 + MX6UL_PAD_CSI_DATA03__USDHC2_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2grp200mhz { + fsl,pins = < + MX6UL_PAD_CSI_HSYNC__USDHC2_CMD 0x170f9 + MX6UL_PAD_CSI_VSYNC__USDHC2_CLK 0x100f9 + MX6UL_PAD_CSI_DATA00__USDHC2_DATA0 0x170f9 + MX6UL_PAD_CSI_DATA01__USDHC2_DATA1 0x170f9 + MX6UL_PAD_CSI_DATA02__USDHC2_DATA2 0x170f9 + MX6UL_PAD_CSI_DATA03__USDHC2_DATA3 0x170f9 + >; + }; + }; +}; + +&pxp { + status = "okay"; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "okay"; + fsl,qspi-has-second-chip = <1>; + ddrsmp=<0>; + + flash0: n25q256a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a"; + spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; + reg = <0>; + }; + + flash1: n25q256a@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a"; + spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; + reg = <1>; + }; + + flash2: n25q256a@2 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a"; + spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; + reg = <2>; + }; + + flash3: n25q256a@3 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a"; + spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; + reg = <3>; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2 + &pinctrl_bt>; + fsl,uart-has-rtscts; + /* for DTE mode, add below change */ + /* fsl,dte-mode; */ + /* pinctrl-0 = <&pinctrl_uart2dte>; */ + status = "okay"; +}; + +&usbotg1 { + vbus-supply = <®_usb_otg1_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_otg1_id>; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + cd-gpios = <&gpio1 19 0>; + wp-gpios = <&gpio1 18 0>; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd1_vmmc>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + cd-gpios = <&gpio4 17 0>; + wp-gpios = <&gpio4 18 0>; + keep-power-in-suspend; + enable-sdio-wakeup; + vmmc-supply = <®_sd2_vmmc>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts index e281d5087d4ad6..c316de3a335213 100644 --- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts +++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts @@ -30,6 +30,11 @@ status = "okay"; }; + pxp_v4l2 { + compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2"; + status = "okay"; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; @@ -43,6 +48,27 @@ gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + reg_can_3v3: regulator@0 { + compatible = "regulator-fixed"; + reg = <0>; + regulator-name = "can-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio_spi 3 GPIO_ACTIVE_LOW>; + }; + + reg_gpio_dvfs: regulator-gpio { + compatible = "regulator-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvfs>; + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1400000>; + regulator-name = "gpio_dvfs"; + regulator-type = "voltage"; + gpios = <&gpio5 3 GPIO_ACTIVE_HIGH>; + states = <1300000 0x1 1400000 0x0>; + }; }; sound { @@ -78,6 +104,30 @@ clocks = <&clks IMX6UL_CLK_SAI2>; }; }; + + spi4 { + compatible = "spi-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi4>; + pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; + status = "okay"; + gpio-sck = <&gpio5 11 0>; + gpio-mosi = <&gpio5 10 0>; + cs-gpios = <&gpio5 7 0>; + num-chipselects = <1>; + #address-cells = <1>; + #size-cells = <0>; + + gpio_spi: gpio_spi@0 { + compatible = "fairchild,74hc595"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + registers-number = <1>; + registers-default = /bits/ 8 <0xb7>; + spi-max-frequency = <100000>; + }; + }; }; &clks { @@ -88,6 +138,7 @@ &cpu0 { arm-supply = <®_arm>; soc-supply = <®_soc>; + dc-supply = <®_gpio_dvfs>; }; &i2c2 { @@ -102,6 +153,36 @@ reg = <0x1a>; wlf,shared-lrclk; }; + + ov5640: ov5640@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_csi1>; + clocks = <&clks IMX6UL_CLK_CSI>; + clock-names = "csi_mclk"; + pwn-gpios = <&gpio_spi 6 1>; + rst-gpios = <&gpio_spi 5 0>; + csi_id = <0>; + mclk = <24000000>; + mclk_source = <0>; + status = "disabled"; + port { + ov5640_ep: endpoint { + remote-endpoint = <&csi1_ep>; + }; + }; + }; +}; + +&csi { + status = "disabled"; + + port { + csi1_ep: endpoint { + remote-endpoint = <&ov5640_ep>; + }; + }; }; &fec1 { @@ -124,15 +205,60 @@ #size-cells = <0>; ethphy0: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; reg = <2>; }; ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; }; }; }; +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can_3v3>; + status = "okay"; +}; + +&gpc { + fsl,cpu_pupscr_sw2iso = <0x1>; + fsl,cpu_pupscr_sw = <0x0>; + fsl,cpu_pdnscr_iso2sw = <0x1>; + fsl,cpu_pdnscr_iso = <0x1>; + fsl,wdog-reset = <1>; /* watchdog select of reset source */ + fsl,ldo-bypass = <0>; /* DCDC, ldo-enable */ +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + mag3110@0e { + compatible = "fsl,mag3110"; + reg = <0x0e>; + position = <2>; + }; + + fxls8471@1e { + compatible = "fsl,fxls8471"; + reg = <0x1e>; + position = <0>; + interrupt-parent = <&gpio5>; + interrupts = <0 8>; + }; +}; &lcdif { pinctrl-names = "default"; @@ -173,16 +299,22 @@ status = "okay"; }; +&pxp { + status = "okay"; +}; + &qspi { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_qspi>; status = "okay"; + ddrsmp=<0>; flash0: n25q256a@0 { #address-cells = <1>; #size-cells = <1>; compatible = "micron,n25q256a"; spi-max-frequency = <29000000>; + spi-nor,ddr-quad-read-dummy = <6>; reg = <0>; }; }; @@ -202,6 +334,17 @@ status = "okay"; }; +&sim2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sim2>; + assigned-clocks = <&clks IMX6UL_CLK_SIM_SEL>; + assigned-clock-parents = <&clks IMX6UL_CLK_SIM_PODF>; + assigned-clock-rates = <240000000>; + pinctrl-assert-gpios = <&gpio4 23 GPIO_ACTIVE_LOW>; + port = <1>; + sven_low_active; +}; + &tsc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tsc>; @@ -264,6 +407,16 @@ &iomuxc { pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog_1>; + + pinctrl_hog_1: hoggrp-1 { + fsl,pins = < + MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0 + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */ + MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */ + MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */ + >; + }; pinctrl_csi1: csi1grp { fsl,pins = < @@ -282,6 +435,12 @@ >; }; + pinctrl_dvfs: dvfsgrp { + fsl,pins = < + MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x79 + >; + }; + pinctrl_enet1: enet1grp { fsl,pins = < MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 @@ -418,6 +577,15 @@ >; }; + pinctrl_spi4: spi4grp { + fsl,pins = < + MX6UL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1 + MX6UL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1 + MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1 + MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000 + >; + }; + pinctrl_tsc: tscgrp { fsl,pins = < MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 @@ -443,6 +611,16 @@ >; }; + pinctrl_uart2dte: uart2dtegrp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DTE_RX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DTE_TX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART2_DTE_CTS 0x1b0b1 + MX6UL_PAD_UART3_TX_DATA__UART2_DTE_RTS 0x1b0b1 + >; + }; + + pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 From c549b0d5631748e76b2ffbcfdf7df196b5c8f00d Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Thu, 30 Jul 2015 02:22:13 +0800 Subject: [PATCH 0045/3047] MLK-11300-04 ARM: imx: add gpt timer support on imx6ul Add gpt-timer for i.MX6UL SOC. Signed-off-by: Bai Ping --- drivers/clocksource/timer-imx-gpt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index f3e2cbb9f15590..9a863fab46e0a0 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -557,4 +557,5 @@ CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6ul_timer, "fsl,imx6ul-gpt", imx6dl_timer_init_dt); CLOCKSOURCE_OF_DECLARE(mx7d_timer, "fsl,imx7d-gpt", imx6dl_timer_init_dt); From 9cc673694a3f36db156b0e0abe2b2ef101bb63a9 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Fri, 31 Jul 2015 18:55:38 +0800 Subject: [PATCH 0046/3047] MLK-11300-05 ARM: imx: add pm support for imx6ul Add basic pm suspend/resume support for i.MX6UL. Signed-off-by: Bai Ping --- arch/arm/mach-imx/common.h | 4 +- arch/arm/mach-imx/hardware.h | 3 +- arch/arm/mach-imx/mach-imx6ul.c | 8 + arch/arm/mach-imx/mx6.h | 51 +++++++ arch/arm/mach-imx/pm-imx6.c | 255 ++++++++++++++++++++----------- arch/arm/mach-imx/suspend-imx6.S | 171 ++++++++++++++++++++- 6 files changed, 395 insertions(+), 97 deletions(-) create mode 100644 arch/arm/mach-imx/mx6.h diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 962eb48e89df6f..a790b97925bef7 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -93,6 +93,7 @@ void imx_smp_prepare(void); static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} #endif +void imx6_pm_map_io(void); void imx7_pm_map_io(void); void imx_src_init(void); void imx_gpc_pre_suspend(bool arm_power_off); @@ -140,6 +141,7 @@ void imx6dl_pm_init(void); void imx6sl_pm_init(void); void imx6sx_pm_init(void); void imx6ul_pm_init(void); +void imx6q_pm_set_ccm_base(void __iomem *base); #ifdef CONFIG_PM void imx51_pm_init(void); diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h index 082e5895387271..fe681cc89c93af 100644 --- a/arch/arm/mach-imx/hardware.h +++ b/arch/arm/mach-imx/hardware.h @@ -109,13 +109,14 @@ #include "mxc.h" -#include "mx7.h" #include "mx3x.h" #include "mx31.h" #include "mx35.h" #include "mx2x.h" #include "mx21.h" #include "mx27.h" +#include "mx6.h" +#include "mx7.h" #define imx_map_entry(soc, name, _type) { \ .virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR), \ diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c index 58a2b88233e665..8540d5125f5f08 100644 --- a/arch/arm/mach-imx/mach-imx6ul.c +++ b/arch/arm/mach-imx/mach-imx6ul.c @@ -73,6 +73,7 @@ static void __init imx6ul_init_machine(void) static void __init imx6ul_init_irq(void) { + imx_gpc_check_dt(); imx_init_revision_from_anatop(); imx_src_init(); irqchip_init(); @@ -87,12 +88,19 @@ static void __init imx6ul_init_late(void) platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); } +static void __init imx6ul_map_io(void) +{ + debug_ll_io_init(); + imx6_pm_map_io(); +} + static const char * const imx6ul_dt_compat[] __initconst = { "fsl,imx6ul", NULL, }; DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)") + .map_io = imx6ul_map_io, .init_irq = imx6ul_init_irq, .init_machine = imx6ul_init_machine, .init_late = imx6ul_init_late, diff --git a/arch/arm/mach-imx/mx6.h b/arch/arm/mach-imx/mx6.h new file mode 100644 index 00000000000000..06b8135a995469 --- /dev/null +++ b/arch/arm/mach-imx/mx6.h @@ -0,0 +1,51 @@ +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License version 2 as + * * published by the Free Software Foundation. + * */ + +#ifndef __ASM_ARCH_MXC_IOMAP_H__ +#define __ASM_ARCH_MXC_IOMAP_H__ + +#define MX6Q_IO_P2V(x) IMX_IO_P2V(x) +#define MX6Q_IO_ADDRESS(x) IOMEM(MX6Q_IO_P2V(x)) + +#define MX6Q_L2_BASE_ADDR 0x00a02000 +#define MX6Q_L2_SIZE 0x1000 +#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000 +#define MX6Q_IOMUXC_SIZE 0x4000 +#define MX6Q_SRC_BASE_ADDR 0x020d8000 +#define MX6Q_SRC_SIZE 0x4000 +#define MX6Q_CCM_BASE_ADDR 0x020c4000 +#define MX6Q_CCM_SIZE 0x4000 +#define MX6Q_ANATOP_BASE_ADDR 0x020c8000 +#define MX6Q_ANATOP_SIZE 0x1000 +#define MX6Q_GPC_BASE_ADDR 0x020dc000 +#define MX6Q_GPC_SIZE 0x4000 +#define MX6Q_SEMA4_BASE_ADDR 0x02290000 +#define MX6Q_SEMA4_SIZE 0x4000 +#define MX6Q_MMDC_P0_BASE_ADDR 0x021b0000 +#define MX6Q_MMDC_P0_SIZE 0x4000 +#define MX6Q_MMDC_P1_BASE_ADDR 0x021b4000 +#define MX6Q_MMDC_P1_SIZE 0x4000 +#define MX6Q_AIPS1_BASE_ADDR 0x02000000 +#define MX6Q_AIPS1_SIZE 0x100000 +#define MX6Q_AIPS2_BASE_ADDR 0x02100000 +#define MX6Q_AIPS2_SIZE 0x100000 +#define MX6Q_AIPS3_BASE_ADDR 0x02200000 +#define MX6Q_AIPS3_SIZE 0x100000 + +#define MX6SX_IRAM_TLB_BASE_ADDR 0x008f8000 +#define MX6Q_IRAM_TLB_BASE_ADDR 0x00900000 +#define MX6Q_IRAM_TLB_SIZE 0x4000 +#define TT_ATTRIB_NON_CACHEABLE_1M 0x802 +#define MX6_SUSPEND_IRAM_DATA_SIZE 256 +#define MX6SL_WFI_IRAM_DATA_SIZE 100 + +#define MX6_SUSPEND_IRAM_ADDR_OFFSET 0 +#define MX6_CPUIDLE_IRAM_ADDR_OFFSET 0x1000 +#endif diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 1515e498d348c6..7833d942df7168 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -19,11 +19,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -64,6 +66,9 @@ #define MX6Q_SUSPEND_OCRAM_SIZE 0x1000 #define MX6_MAX_MMDC_IO_NUM 33 +extern unsigned long iram_tlb_base_addr; +extern unsigned long iram_tlb_phys_addr; + static void __iomem *ccm_base; static void __iomem *suspend_ocram_base; static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); @@ -195,6 +200,36 @@ static const struct imx6_pm_socdata imx6ul_pm_data __initconst = { .mmdc_io_offset = imx6ul_mmdc_io_offset, }; +static struct map_desc iram_tlb_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_1M, + .type = MT_MEMORY_RWX_NONCACHED, +}; + +/* + * AIPS1 and AIPS2 is not used, because it will trigger a BUG_ON if + * lowlevel debug and earlyprintk are configured. + * + * it is because there is a vm conflict because UART1 is mapped early if + * AIPS1 is mapped using 1M size. + * + * Thus no use AIPS1 and AIPS2 to avoid kernel BUG_ON. + */ +static struct map_desc imx6_pm_io_desc[] __initdata = { + imx_map_entry(MX6Q, MMDC_P0, MT_DEVICE), + imx_map_entry(MX6Q, MMDC_P1, MT_DEVICE), + imx_map_entry(MX6Q, SRC, MT_DEVICE), + imx_map_entry(MX6Q, IOMUXC, MT_DEVICE), + imx_map_entry(MX6Q, CCM, MT_DEVICE), + imx_map_entry(MX6Q, ANATOP, MT_DEVICE), + imx_map_entry(MX6Q, GPC, MT_DEVICE), +}; + +static const char * const low_power_ocram_match[] __initconst = { + "fsl,lpm-sram", + NULL +}; + /* * This structure is for passing necessary data for low level ocram * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct @@ -213,6 +248,8 @@ struct imx6_cpu_pm_info { struct imx6_pm_base ccm_base; struct imx6_pm_base gpc_base; struct imx6_pm_base l2_base; + struct imx6_pm_base anatop_base; + u32 ttbr1; /* Store TTBR1 */ u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ } __aligned(8); @@ -418,42 +455,108 @@ static const struct platform_suspend_ops imx6q_pm_ops = { .valid = imx6q_pm_valid, }; -static int __init imx6_pm_get_base(struct imx6_pm_base *base, - const char *compat) +static int __init imx6_dt_find_lpsram(unsigned long node, const char *uname, + int depth, void *data) { - struct device_node *node; - struct resource res; - int ret = 0; + unsigned long lpram_addr; + const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL); + + if (of_flat_dt_match(node, low_power_ocram_match)) { + if (!prop) + return -EINVAL; + + lpram_addr = be32_to_cpup(prop); + + /* We need to create a 1M page table entry. */ + iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000); + iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000); + iram_tlb_phys_addr = lpram_addr; + iram_tlb_base_addr = IMX_IO_P2V(lpram_addr); - node = of_find_compatible_node(NULL, NULL, compat); - if (!node) { - ret = -ENODEV; - goto out; + iotable_init(&iram_tlb_io_desc, 1); } - ret = of_address_to_resource(node, 0, &res); - if (ret) - goto put_node; + return 0; +} - base->pbase = res.start; - base->vbase = ioremap(res.start, resource_size(&res)); - if (!base->vbase) - ret = -ENOMEM; +void __init imx6_pm_map_io(void) +{ + unsigned long i; -put_node: - of_node_put(node); -out: - return ret; + pr_info("pm_map_io init\n\n"); + + iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); + + /* + * Get the address of IRAM or OCRAM to be used by the low + * power code from the device tree. + */ + WARN_ON(of_scan_flat_dt(imx6_dt_find_lpsram, NULL)); + + /* Return if no IRAM space is allocated for suspend/resume code. */ + if (!iram_tlb_base_addr) { + pr_warn("No IRAM/OCRAM memory allocated for suspend/resume \ + code. Please ensure device tree has an entry for \ + fsl,lpm-sram.\n"); + return; + } + + /* Set all entries to 0. */ + memset((void *)iram_tlb_base_addr, 0, MX6Q_IRAM_TLB_SIZE); + + /* + * Make sure the IRAM virtual address has a mapping in the IRAM + * page table. + * + * Only use the top 11 bits [31-20] when storing the physical + * address in the page table as only these bits are required + * for 1M mapping. + */ + i = ((iram_tlb_base_addr >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS1 virtual address has a mapping in the + * IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_AIPS1_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_AIPS1_BASE_ADDR & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS2 virtual address has a mapping in the + * IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_AIPS2_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_AIPS2_BASE_ADDR & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the AIPS3 virtual address has a mapping + * in the IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_AIPS3_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_AIPS3_BASE_ADDR & 0xFFF00000) | + TT_ATTRIB_NON_CACHEABLE_1M; + + /* + * Make sure the L2 controller virtual address has a mapping + * in the IRAM page table. + */ + i = ((IMX_IO_P2V(MX6Q_L2_BASE_ADDR) >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (MX6Q_L2_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; } static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) { - phys_addr_t ocram_pbase; struct device_node *node; - struct platform_device *pdev; struct imx6_cpu_pm_info *pm_info; - struct gen_pool *ocram_pool; - unsigned long ocram_base; + unsigned long iram_paddr; int i, ret = 0; const u32 *mmdc_offset_array; @@ -464,41 +567,24 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) return -EINVAL; } - node = of_find_compatible_node(NULL, NULL, "mmio-sram"); - if (!node) { - pr_warn("%s: failed to find ocram node!\n", __func__); - return -ENODEV; - } - - pdev = of_find_device_by_node(node); - if (!pdev) { - pr_warn("%s: failed to find ocram device!\n", __func__); - ret = -ENODEV; - goto put_node; - } - - ocram_pool = gen_pool_get(&pdev->dev, NULL); - if (!ocram_pool) { - pr_warn("%s: ocram pool unavailable!\n", __func__); - ret = -ENODEV; - goto put_node; - } - - ocram_base = gen_pool_alloc(ocram_pool, MX6Q_SUSPEND_OCRAM_SIZE); - if (!ocram_base) { - pr_warn("%s: unable to alloc ocram!\n", __func__); - ret = -ENOMEM; - goto put_node; - } + /* + * 16KB is allocated for IRAM TLB, but only up 8k is for kernel TLB, + * The lower 8K is not used, so use the lower 8K for IRAM code and + * pm_info. + * + */ + iram_paddr = iram_tlb_phys_addr + MX6_SUSPEND_IRAM_ADDR_OFFSET; - ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base); + /* Make sure iram_paddr is 8 byte aligned. */ + if ((uintptr_t)(iram_paddr) & (FNCPY_ALIGN - 1)) + iram_paddr += FNCPY_ALIGN - iram_paddr % (FNCPY_ALIGN); - suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, - MX6Q_SUSPEND_OCRAM_SIZE, false); + /* Get the virtual address of the suspend code. */ + suspend_ocram_base = (void *)IMX_IO_P2V(iram_paddr); memset(suspend_ocram_base, 0, sizeof(*pm_info)); pm_info = suspend_ocram_base; - pm_info->pbase = ocram_pbase; + pm_info->pbase = iram_paddr; pm_info->resume_addr = virt_to_phys(v7_cpu_resume); pm_info->pm_info_size = sizeof(*pm_info); @@ -506,40 +592,33 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) * ccm physical address is not used by asm code currently, * so get ccm virtual address directly. */ - pm_info->ccm_base.vbase = ccm_base; + pm_info->ccm_base.pbase = MX6Q_CCM_BASE_ADDR; + pm_info->ccm_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_CCM_BASE_ADDR); - ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat); - if (ret) { - pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret); - goto put_node; - } + pm_info->mmdc_base.pbase = MX6Q_MMDC_P0_BASE_ADDR; + pm_info->mmdc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR); - ret = imx6_pm_get_base(&pm_info->src_base, socdata->src_compat); - if (ret) { - pr_warn("%s: failed to get src base %d!\n", __func__, ret); - goto src_map_failed; - } + pm_info->src_base.pbase = MX6Q_SRC_BASE_ADDR; + pm_info->src_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_SRC_BASE_ADDR); - ret = imx6_pm_get_base(&pm_info->iomuxc_base, socdata->iomuxc_compat); - if (ret) { - pr_warn("%s: failed to get iomuxc base %d!\n", __func__, ret); - goto iomuxc_map_failed; - } + pm_info->iomuxc_base.pbase = MX6Q_IOMUXC_BASE_ADDR; + pm_info->iomuxc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR); - ret = imx6_pm_get_base(&pm_info->gpc_base, socdata->gpc_compat); - if (ret) { - pr_warn("%s: failed to get gpc base %d!\n", __func__, ret); - goto gpc_map_failed; - } + pm_info->gpc_base.pbase = MX6Q_GPC_BASE_ADDR; + pm_info->gpc_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_GPC_BASE_ADDR); - if (socdata->pl310_compat) { - ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat); - if (ret) { - pr_warn("%s: failed to get pl310-cache base %d!\n", - __func__, ret); - goto pl310_cache_map_failed; - } - } + pm_info->l2_base.pbase = MX6Q_L2_BASE_ADDR; + pm_info->l2_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_L2_BASE_ADDR); + + pm_info->anatop_base.pbase = MX6Q_ANATOP_BASE_ADDR; + pm_info->anatop_base.vbase = (void __iomem *) + IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR); pm_info->ddr_type = imx_mmdc_get_ddr_type(); pm_info->mmdc_io_num = socdata->mmdc_io_num; @@ -560,14 +639,6 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) goto put_node; -pl310_cache_map_failed: - iounmap(pm_info->gpc_base.vbase); -gpc_map_failed: - iounmap(pm_info->iomuxc_base.vbase); -iomuxc_map_failed: - iounmap(pm_info->src_base.vbase); -src_map_failed: - iounmap(pm_info->mmdc_base.vbase); put_node: of_node_put(node); diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index 76ee2ceec8d546..85bde115f1284c 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -1,5 +1,5 @@ /* - * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2014-2015 Freescale Semiconductor, Inc. * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License @@ -59,8 +59,11 @@ #define PM_INFO_MX6Q_GPC_V_OFFSET 0x34 #define PM_INFO_MX6Q_L2_P_OFFSET 0x38 #define PM_INFO_MX6Q_L2_V_OFFSET 0x3C -#define PM_INFO_MMDC_IO_NUM_OFFSET 0x40 -#define PM_INFO_MMDC_IO_VAL_OFFSET 0x44 +#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x40 +#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x44 +#define PM_INFO_MX6Q_TTBR1_V_OFFSET 0x48 +#define PM_INFO_MMDC_IO_NUM_OFFSET 0x4c +#define PM_INFO_MMDC_IO_VAL_OFFSET 0x50 #define MX6Q_SRC_GPR1 0x20 #define MX6Q_SRC_GPR2 0x24 @@ -74,6 +77,45 @@ .align 3 + /* Check if the cpu is cortex-a7 */ + .macro is_cortex_a7 + + /* Read the primary cpu number is MPIDR */ + mrc p15, 0, r5, c0, c0, 0 + ldr r6, =0xfff0 + and r5, r5, r6 + ldr r6, =0xc070 + cmp r5, r6 + + .endm + + .macro disable_l1_cache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0 - r10, lr} + ldr r7, =v7_flush_dcache_all + mov lr, pc + mov pc, r7 + pop {r0 - r10, lr} + + /* disable d-cache */ + mrc p15, 0, r7, c1, c0, 0 + bic r7, r7, #(1 << 2) + mcr p15, 0, r7, c1, c0, 0 + dsb + isb + + push {r0 -r10, lr} + ldr r7, = v7_flush_dcache_all + mov lr, pc + mov pc , r7 + pop {r0 -r10, lr} + + .endm + .macro sync_l2_cache /* sync L2 cache to drain L2's buffers to DRAM. */ @@ -151,6 +193,111 @@ .endm + .macro store_ttbr1 + + /* Store TTBR1 to pm_info->ttbr1 */ + mrc p15, 0, r7, c2, c0, 1 + str r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET] + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r6, [r6] + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r6, c2, c0, 1 + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + is_cortex_a7 + beq 14f + +#ifdef CONFIG_CACHE_L2X0 + ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + mov r6, #0x0 + str r6, [r8, #0x100] + + dsb + isb +#endif +14: + .endm + + .macro restore_ttbr1 + + is_cortex_a7 + beq 15f + +#ifdef CONFIG_CACHE_L2X0 + /* Enable L2. */ + ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] + ldr r7, =0x1 + str r7, [r8, #0x100] +#endif + +15: + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Restore TTBCR */ + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Restore TTBR1, get the origin ttbr1 from pm info */ + ldr r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET] + mcr p15, 0, r7, c2, c0, 1 + + .endm + + ENTRY(imx6_suspend) ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] @@ -185,8 +332,22 @@ ENTRY(imx6_suspend) str r9, [r11, #MX6Q_SRC_GPR1] str r1, [r11, #MX6Q_SRC_GPR2] + /* + * Check if the cpu is Cortex-A7, for Cortex-A7 + * the cache implementation is not the same as + * Cortex-A9, so the cache maintenance operation + * is different. + */ + is_cortex_a7 + beq a7_dache_flush + /* need to sync L2 cache before DSM. */ sync_l2_cache + b ttbr_store +a7_dache_flush: + disable_l1_cache +ttbr_store: + store_ttbr1 ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] /* @@ -305,6 +466,7 @@ rbc_loop: */ mov r5, #0x0 resume_mmdc + restore_ttbr1 /* return to suspend finish */ ret lr @@ -342,8 +504,11 @@ ENDPROC(imx6_suspend) ENTRY(v7_cpu_resume) bl v7_invalidate_l1 + is_cortex_a7 + beq done #ifdef CONFIG_CACHE_L2X0 bl l2c310_early_resume #endif +done: b cpu_resume ENDPROC(v7_cpu_resume) From 3e6c90335e0b7fbb43cd82c77fdfc750b565e391 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Fri, 31 Jul 2015 22:06:36 +0800 Subject: [PATCH 0047/3047] MLK-11300-06 ARM: configs: enable imx6ul in defconfig Enable the i.MX6UL SOC support in the defconfig file. Signed-off-by: Bai Ping --- arch/arm/configs/imx_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 0933afae79f050..11d7fd7fb1abd7 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -25,6 +25,7 @@ CONFIG_SOC_IMX53=y CONFIG_SOC_IMX6Q=y CONFIG_SOC_IMX6SL=y CONFIG_SOC_IMX6SX=y +CONFIG_SOC_IMX6UL=y CONFIG_SOC_IMX7D=y CONFIG_SOC_VF610=y CONFIG_SMP=y From 65af541e3c5c373b420431766a64165bafc99fee Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 18 Aug 2015 11:28:08 +0800 Subject: [PATCH 0048/3047] MLK-11317-02 ARM: imx: imx6ul: add enet init for i.mx6ul Add enet MAC address init. The patch is merged from commit: 67cfceab0b77e887910f11dda13ab3a98bb0d87a Signed-off-by: Fugang Duan --- arch/arm/mach-imx/mach-imx6ul.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c index 8540d5125f5f08..af30a0773cfe7f 100644 --- a/arch/arm/mach-imx/mach-imx6ul.c +++ b/arch/arm/mach-imx/mach-imx6ul.c @@ -55,6 +55,7 @@ static inline void imx6ul_enet_init(void) { imx6ul_enet_clk_init(); imx6ul_enet_phy_init(); + imx6_enet_mac_init("fsl,imx6ul-fec", "fsl,imx6ul-ocotp"); } static void __init imx6ul_init_machine(void) From 2a98b521787d64cf5dc7bf7d5efbd8b84b8086ce Mon Sep 17 00:00:00 2001 From: Fancy Fang Date: Tue, 4 Aug 2015 15:51:54 +0800 Subject: [PATCH 0049/3047] MLK-11318-2 ARM: dts: imx7d-sdb: add dts support for pwm backlight Add dts support for pwm backlight on imx_4.1.y branch. Signed-off-by: Fancy Fang --- arch/arm/boot/dts/imx7d-sdb.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 43c264d27110e5..b55ba3c70d95c3 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -93,6 +93,15 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; + + }; + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + status = "okay"; }; spi4 { From 456cd7bbe83743278418c2f21ae591dd4194a7c4 Mon Sep 17 00:00:00 2001 From: Fancy Fang Date: Tue, 4 Aug 2015 16:05:20 +0800 Subject: [PATCH 0050/3047] MLK-11318-3 ARM: dts: imx7d-12x12-lpddr3-arm2: add dts support for lcdif Add dts support for lcdif on imx_4.1.y branch. Signed-off-by: Fancy Fang --- arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts index f15c8da01d3cb5..1793e13fac0793 100644 --- a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts @@ -281,6 +281,44 @@ >; }; + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX7D_PAD_EPDC_DATA00__LCD_DATA0 0x4001b0b0 + MX7D_PAD_EPDC_DATA01__LCD_DATA1 0x4001b0b0 + MX7D_PAD_EPDC_DATA02__LCD_DATA2 0x4001b0b0 + MX7D_PAD_EPDC_DATA03__LCD_DATA3 0x4001b0b0 + MX7D_PAD_EPDC_DATA04__LCD_DATA4 0x4001b0b0 + MX7D_PAD_EPDC_DATA05__LCD_DATA5 0x4001b0b0 + MX7D_PAD_EPDC_DATA06__LCD_DATA6 0x4001b0b0 + MX7D_PAD_EPDC_DATA07__LCD_DATA7 0x4001b0b0 + MX7D_PAD_EPDC_DATA08__LCD_DATA8 0x4001b0b0 + MX7D_PAD_EPDC_DATA09__LCD_DATA9 0x4001b0b0 + MX7D_PAD_EPDC_DATA10__LCD_DATA10 0x4001b0b0 + MX7D_PAD_EPDC_DATA11__LCD_DATA11 0x4001b0b0 + MX7D_PAD_EPDC_DATA12__LCD_DATA12 0x4001b0b0 + MX7D_PAD_EPDC_DATA13__LCD_DATA13 0x4001b0b0 + MX7D_PAD_EPDC_DATA14__LCD_DATA14 0x4001b0b0 + MX7D_PAD_EPDC_DATA15__LCD_DATA15 0x4001b0b0 + MX7D_PAD_EPDC_SDLE__LCD_DATA16 0x4001b0b0 + MX7D_PAD_EPDC_SDOE__LCD_DATA17 0x4001b0b0 + MX7D_PAD_EPDC_SDSHR__LCD_DATA18 0x4001b0b0 + MX7D_PAD_EPDC_SDCE0__LCD_DATA19 0x4001b0b0 + MX7D_PAD_EPDC_SDCE1__LCD_DATA20 0x4001b0b0 + MX7D_PAD_EPDC_SDCE2__LCD_DATA21 0x4001b0b0 + MX7D_PAD_EPDC_SDCE3__LCD_DATA22 0x4001b0b0 + MX7D_PAD_EPDC_GDCLK__LCD_DATA23 0x4001b0b0 + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX7D_PAD_EPDC_SDCLK__LCD_CLK 0x4001b0b0 + MX7D_PAD_EPDC_BDR1__LCD_ENABLE 0x4001b0b0 + MX7D_PAD_EPDC_PWR_STAT__LCD_VSYNC 0x4001b0b0 + MX7D_PAD_EPDC_PWR_COM__LCD_HSYNC 0x4001b0b0 + >; + }; + pinctrl_uart1_1: uart1grp-1 { fsl,pins = < MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 @@ -349,6 +387,38 @@ }; }; +&lcdif { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcdif_dat + &pinctrl_lcdif_ctrl>; + display = <&display0>; + status = "okay"; + + display0: display { + bits-per-pixel = <16>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hback-porch = <89>; + hfront-porch = <164>; + vback-porch = <23>; + vfront-porch = <10>; + hsync-len = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1_1>; From 07b6692d0b23487ead68ba201e2ffc0277544ca0 Mon Sep 17 00:00:00 2001 From: Fancy Fang Date: Tue, 4 Aug 2015 16:08:51 +0800 Subject: [PATCH 0051/3047] MLK-11318-4 ARM: dts: imx7d-12x12-lpddr3-arm2: add dts support for pwm backlight Add dts support for pwm backlight on imx_4.1.y branch. Signed-off-by: Fancy Fang --- arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts index 1793e13fac0793..e94a10c8baef54 100644 --- a/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts +++ b/arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts @@ -14,6 +14,14 @@ model = "Freescale i.MX7 LPDDR3 12x12 ARM2 Board"; compatible = "fsl,imx7d-12x12-lpddr3-arm2", "fsl,imx7d"; + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 5000000>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + status = "okay"; + }; + regulators { compatible = "simple-bus"; @@ -319,6 +327,12 @@ >; }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX7D_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 + >; + }; + pinctrl_uart1_1: uart1grp-1 { fsl,pins = < MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79 @@ -419,6 +433,12 @@ }; }; +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1_1>; From b322f245a8c9e6be624799ecce3fee388fb0ebe8 Mon Sep 17 00:00:00 2001 From: Fancy Fang Date: Tue, 4 Aug 2015 17:23:45 +0800 Subject: [PATCH 0052/3047] MLK-11318-5: video: mxsfb: porting mxsfb driver to imx_4.1.y branch Porting mxsfb driver to imx_4.1.y branch. Signed-off-by: Fancy Fang --- arch/arm/configs/imx_v7_defconfig | 1 + drivers/video/fbdev/Kconfig | 4 + drivers/video/fbdev/Makefile | 1 + drivers/video/fbdev/mxc/Kconfig | 19 + drivers/video/fbdev/mxc/Makefile | 1 + drivers/video/fbdev/mxc/crtc.h | 57 ++ drivers/video/fbdev/mxc/mxc_dispdrv.c | 148 +++++ drivers/video/fbdev/mxc/mxc_dispdrv.h | 52 ++ drivers/video/fbdev/mxsfb.c | 917 +++++++++++++++++++++----- include/linux/mxcfb.h | 46 ++ include/uapi/linux/mxcfb.h | 198 ++++++ 11 files changed, 1282 insertions(+), 162 deletions(-) create mode 100644 drivers/video/fbdev/mxc/Kconfig create mode 100644 drivers/video/fbdev/mxc/Makefile create mode 100644 drivers/video/fbdev/mxc/crtc.h create mode 100644 drivers/video/fbdev/mxc/mxc_dispdrv.c create mode 100644 drivers/video/fbdev/mxc/mxc_dispdrv.h create mode 100644 include/linux/mxcfb.h create mode 100644 include/uapi/linux/mxcfb.h diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 11d7fd7fb1abd7..740dde92ef9262 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -226,6 +226,7 @@ CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_L4F00242T03=y CONFIG_LCD_PLATFORM=y CONFIG_BACKLIGHT_PWM=y +CONFIG_FB_MXC_SYNC_PANEL=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 5d3b0db5ce0af3..77a0457fd1d487 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2449,6 +2449,10 @@ source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" +if ARCH_MXC +source "drivers/video/fbdev/mxc/Kconfig" +endif + config FB_SH_MOBILE_MERAM tristate "SuperH Mobile MERAM read ahead support" depends on (SUPERH || ARCH_SHMOBILE) diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index ee8c81405a7f9a..098f3b5d1066a2 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_FB_KYRO) += kyro/ obj-$(CONFIG_FB_SAVAGE) += savage/ obj-$(CONFIG_FB_GEODE) += geode/ obj-$(CONFIG_FB_MBX) += mbx/ +obj-$(CONFIG_FB_MXC) += mxc/ obj-$(CONFIG_FB_NEOMAGIC) += neofb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o diff --git a/drivers/video/fbdev/mxc/Kconfig b/drivers/video/fbdev/mxc/Kconfig new file mode 100644 index 00000000000000..e9feb1885daf56 --- /dev/null +++ b/drivers/video/fbdev/mxc/Kconfig @@ -0,0 +1,19 @@ +config FB_MXC + tristate "MXC Framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_MODE_HELPERS + default y + help + This is a framebuffer device for the MXC LCD Controller. + See for information on framebuffer + devices. + + If you plan to use the LCD display with your MXC system, say + Y here. + +config FB_MXC_SYNC_PANEL + depends on FB_MXC + tristate "Synchronous Panel Framebuffer" diff --git a/drivers/video/fbdev/mxc/Makefile b/drivers/video/fbdev/mxc/Makefile new file mode 100644 index 00000000000000..568574e82b1540 --- /dev/null +++ b/drivers/video/fbdev/mxc/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o diff --git a/drivers/video/fbdev/mxc/crtc.h b/drivers/video/fbdev/mxc/crtc.h new file mode 100644 index 00000000000000..8bd1c1b95bd19e --- /dev/null +++ b/drivers/video/fbdev/mxc/crtc.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __CRTC__ +#define __CRTC__ + +enum crtc { + CRTC_IPU_DI0, + CRTC_IPU_DI1, + CRTC_IPU1_DI0, + CRTC_IPU1_DI1, + CRTC_IPU2_DI0, + CRTC_IPU2_DI1, + CRTC_LCDIF, + CRTC_LCDIF1, + CRTC_LCDIF2, + CRTC_MAX, +}; + +struct ipu_di_crtc_map { + enum crtc crtc; + int ipu_id; + int ipu_di; +}; + +static const struct ipu_di_crtc_map ipu_di_crtc_maps[] = { + {CRTC_IPU1_DI0, 0 , 0}, {CRTC_IPU1_DI1, 0 , 1}, + {CRTC_IPU2_DI0, 1 , 0}, {CRTC_IPU2_DI1, 1 , 1}, +}; + +static inline int ipu_di_to_crtc(struct device *dev, int ipu_id, + int ipu_di, enum crtc *crtc) +{ + int i = 0; + + for (; i < ARRAY_SIZE(ipu_di_crtc_maps); i++) + if (ipu_di_crtc_maps[i].ipu_id == ipu_id && + ipu_di_crtc_maps[i].ipu_di == ipu_di) { + *crtc = ipu_di_crtc_maps[i].crtc; + return 0; + } + + dev_err(dev, "failed to get valid ipu di crtc " + "ipu_id %d, ipu_di %d\n", ipu_id, ipu_di); + return -EINVAL; +} + +#endif diff --git a/drivers/video/fbdev/mxc/mxc_dispdrv.c b/drivers/video/fbdev/mxc/mxc_dispdrv.c new file mode 100644 index 00000000000000..805c1c98b0f92d --- /dev/null +++ b/drivers/video/fbdev/mxc/mxc_dispdrv.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file mxc_dispdrv.c + * @brief mxc display driver framework. + * + * A display device driver could call mxc_dispdrv_register(drv) in its dev_probe() function. + * Move all dev_probe() things into mxc_dispdrv_driver->init(), init() function should init + * and feedback setting; + * Move all dev_remove() things into mxc_dispdrv_driver->deinit(); + * Move all dev_suspend() things into fb_notifier for SUSPEND, if there is; + * Move all dev_resume() things into fb_notifier for RESUME, if there is; + * + * mxc fb driver could call mxc_dispdrv_gethandle(name, setting) before a fb + * need be added, with fbi param passing by setting, after + * mxc_dispdrv_gethandle() return, FB driver should get the basic setting + * about fbi info and crtc. + * + * @ingroup Framebuffer + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mxc_dispdrv.h" + +static LIST_HEAD(dispdrv_list); +static DEFINE_MUTEX(dispdrv_lock); + +struct mxc_dispdrv_entry { + /* Note: drv always the first element */ + struct mxc_dispdrv_driver *drv; + bool active; + void *priv; + struct list_head list; +}; + +struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv) +{ + struct mxc_dispdrv_entry *new; + + mutex_lock(&dispdrv_lock); + + new = kzalloc(sizeof(struct mxc_dispdrv_entry), GFP_KERNEL); + if (!new) { + mutex_unlock(&dispdrv_lock); + return ERR_PTR(-ENOMEM); + } + + new->drv = drv; + list_add_tail(&new->list, &dispdrv_list); + + mutex_unlock(&dispdrv_lock); + + return (struct mxc_dispdrv_handle *)new; +} +EXPORT_SYMBOL_GPL(mxc_dispdrv_register); + +int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle) +{ + struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle; + + if (entry) { + mutex_lock(&dispdrv_lock); + list_del(&entry->list); + mutex_unlock(&dispdrv_lock); + kfree(entry); + return 0; + } else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(mxc_dispdrv_unregister); + +struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name, + struct mxc_dispdrv_setting *setting) +{ + int ret, found = 0; + struct mxc_dispdrv_entry *entry; + + mutex_lock(&dispdrv_lock); + list_for_each_entry(entry, &dispdrv_list, list) { + if (!strcmp(entry->drv->name, name) && (entry->drv->init)) { + ret = entry->drv->init((struct mxc_dispdrv_handle *) + entry, setting); + if (ret >= 0) { + entry->active = true; + found = 1; + break; + } + } + } + mutex_unlock(&dispdrv_lock); + + return found ? (struct mxc_dispdrv_handle *)entry:ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(mxc_dispdrv_gethandle); + +void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle) +{ + struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle; + + mutex_lock(&dispdrv_lock); + if (entry && entry->active && entry->drv->deinit) { + entry->drv->deinit(handle); + entry->active = false; + } + mutex_unlock(&dispdrv_lock); + +} +EXPORT_SYMBOL_GPL(mxc_dispdrv_puthandle); + +int mxc_dispdrv_setdata(struct mxc_dispdrv_handle *handle, void *data) +{ + struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle; + + if (entry) { + entry->priv = data; + return 0; + } else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(mxc_dispdrv_setdata); + +void *mxc_dispdrv_getdata(struct mxc_dispdrv_handle *handle) +{ + struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle; + + if (entry) { + return entry->priv; + } else + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(mxc_dispdrv_getdata); diff --git a/drivers/video/fbdev/mxc/mxc_dispdrv.h b/drivers/video/fbdev/mxc/mxc_dispdrv.h new file mode 100644 index 00000000000000..58d8a07d33801a --- /dev/null +++ b/drivers/video/fbdev/mxc/mxc_dispdrv.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __MXC_DISPDRV_H__ +#define __MXC_DISPDRV_H__ +#include +#include "crtc.h" + +struct mxc_dispdrv_handle { + struct mxc_dispdrv_driver *drv; +}; + +struct mxc_dispdrv_setting { + /*input-feedback parameter*/ + struct fb_info *fbi; + int if_fmt; + int default_bpp; + char *dft_mode_str; + + /* feedback parameter */ + enum crtc crtc; +}; + +struct mxc_dispdrv_driver { + const char *name; + int (*init) (struct mxc_dispdrv_handle *, struct mxc_dispdrv_setting *); + void (*deinit) (struct mxc_dispdrv_handle *); + /* display driver enable function for extension */ + int (*enable) (struct mxc_dispdrv_handle *, struct fb_info *); + /* display driver disable function, called at early part of fb_blank */ + void (*disable) (struct mxc_dispdrv_handle *, struct fb_info *); + /* display driver setup function, called at early part of fb_set_par */ + int (*setup) (struct mxc_dispdrv_handle *, struct fb_info *fbi); +}; + +struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv); +int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle); +struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name, + struct mxc_dispdrv_setting *setting); +void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle); +int mxc_dispdrv_setdata(struct mxc_dispdrv_handle *handle, void *data); +void *mxc_dispdrv_getdata(struct mxc_dispdrv_handle *handle); +#endif diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c index 7846f0e8bbbb55..6b0df19604deb4 100644 --- a/drivers/video/fbdev/mxsfb.c +++ b/drivers/video/fbdev/mxsfb.c @@ -4,7 +4,7 @@ * This code is based on: * Author: Vitaly Wool * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2015 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -39,18 +39,25 @@ * the required value in the imx_fb_videomode structure. */ +#include #include #include #include #include +#include +#include #include #include #include +#include #include +#include #include #include