imx6dl-sabreauto.dtb \
imx6dl-sabrelite.dtb \
imx6dl-sabresd.dtb \
+ imx6dl-tx6dl-comtft.dtb \
imx6dl-tx6u-801x.dtb \
+ imx6dl-tx6u-811x.dtb \
imx6dl-wandboard.dtb \
imx6q-arm2.dtb \
imx6q-cm-fx6.dtb \
imx6q-sabrelite.dtb \
imx6q-sabresd.dtb \
imx6q-sbc6x.dtb \
- imx6q-udoo.dtb \
- imx6q-wandboard.dtb \
- imx6sl-evk.dtb \
- vf610-colibri.dtb \
- vf610-cosmic.dtb \
- vf610-twr.dtb
-# imx6dl-tx6dl-comtft.dtb \
- imx6dl-tx6u-801x.dtb \
- imx6dl-tx6u-811x.dtb \
- imx6dl-wandboard.dtb \
- imx6q-arm2.dtb \
- imx6q-sabreauto.dtb \
- imx6q-sabreauto-ecspi.dtb \
- imx6q-sabreauto-flexcan1.dtb \
- imx6q-sabreauto-gpmi-weim.dtb \
- imx6q-sabrelite.dtb \
- imx6q-sabresd.dtb \
- imx6q-sabresd-hdcp.dtb \
- imx6q-sabresd-ldo.dtb \
- imx6q-sbc6x.dtb \
imx6q-tx6q-1010.dtb \
imx6q-tx6q-1010-comtft.dtb \
imx6q-tx6q-1020.dtb \
imx6q-tx6q-1020-comtft.dtb \
imx6q-tx6q-1110.dtb \
+ imx6q-udoo.dtb \
+ imx6q-wandboard.dtb \
imx6sl-evk.dtb \
- imx6sl-evk-csi.dtb \
- imx6sl-evk-ldo.dtb \
+ vf610-colibri.dtb \
+ vf610-cosmic.dtb \
vf610-twr.dtb
dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \
imx23-olinuxino.dtb \
};
soc {
+
+ busfreq { /* BUSFREQ */
+ compatible = "fsl,imx6_busfreq";
+ clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>,
+ <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>, <&clks 22> , <&clks 8>;
+ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph",
+ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "axi_sel", "pll3_pfd1_540m";
+ interrupts = <0 107 0x04>, <0 112 0x4>;
+ interrupt-names = "irq_busfreq_0", "irq_busfreq_1";
+ fsl,max_ddr_freq = <400000000>;
+ };
+
+ gpu: gpu@00130000 {
+ compatible = "fsl,imx6dl-gpu", "fsl,imx6q-gpu";
+ reg = <0x00130000 0x4000>, <0x00134000 0x4000>,
+ <0x0 0x0>;
+ reg-names = "iobase_3d", "iobase_2d",
+ "phys_baseaddr";
+ interrupts = <0 9 0x04>, <0 10 0x04>;
+ interrupt-names = "irq_3d", "irq_2d";
+ clocks = <&clks 143>, <&clks 27>,
+ <&clks 121>, <&clks 122>,
+ <&clks 0>;
+ clock-names = "gpu2d_axi_clk", "gpu3d_axi_clk",
+ "gpu2d_clk", "gpu3d_clk",
+ "gpu3d_shader_clk";
+ resets = <&src 0>, <&src 3>;
+ reset-names = "gpu3d", "gpu2d";
+ pu-supply = <®_pu>;
+ };
+
ocram: sram@00900000 {
compatible = "mmio-sram";
- reg = <0x00900000 0x20000>;
+ reg = <0x00904000 0x1C000>;
clocks = <&clks 142>;
};
+ hdmi_core: hdmi_core@00120000 {
+ compatible = "fsl,imx6dl-hdmi-core";
+ reg = <0x00120000 0x9000>;
+ clocks = <&clks 124>, <&clks 123>;
+ clock-names = "hdmi_isfr", "hdmi_iahb";
+ status = "disabled";
+ };
+
+ hdmi_video: hdmi_video@020e0000 {
+ compatible = "fsl,imx6dl-hdmi-video";
+ reg = <0x020e0000 0x1000>;
+ reg-names = "hdmi_gpr";
+ interrupts = <0 115 0x04>;
+ clocks = <&clks 124>, <&clks 123>;
+ clock-names = "hdmi_isfr", "hdmi_iahb";
+ status = "disabled";
+ };
+
+ hdmi_audio: hdmi_audio@00120000 {
+ compatible = "fsl,imx6dl-hdmi-audio";
+ clocks = <&clks 124>, <&clks 123>;
+ clock-names = "hdmi_isfr", "hdmi_iahb";
+ dmas = <&sdma 2 22 0>;
+ dma-names = "tx";
+ status = "disabled";
+ };
+
+ hdmi_cec: hdmi_cec@00120000 {
+ compatible = "fsl,imx6dl-hdmi-cec";
+ interrupts = <0 115 0x04>;
+ status = "disabled";
+ };
+
aips1: aips-bus@02000000 {
+ vpu@02040000 {
+ compatible = "fsl,imx6dl-vpu";
+ iramsize = <0>;
+ status = "okay";
+ };
+
iomuxc: iomuxc@020e0000 {
compatible = "fsl,imx6dl-iomuxc";
};
pxp: pxp@020f0000 {
+ compatible = "fsl,imx6dl-pxp-dma";
reg = <0x020f0000 0x4000>;
interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks 133>;
+ clock-names = "pxp-axi";
+ status = "disabled";
};
epdc: epdc@020f4000 {
+ compatible = "fsl,imx6dl-epdc";
reg = <0x020f4000 0x4000>;
interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks 133>, <&clks 137>;
+ clock-names = "epdc_axi", "epdc_pix";
};
lcdif: lcdif@020f8000 {
};
aips2: aips-bus@02100000 {
+ mipi_dsi: mipi@021e0000 {
+ compatible = "fsl,imx6dl-mipi-dsi";
+ reg = <0x021e0000 0x4000>;
+ interrupts = <0 102 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 138>, <&clks 204>;
+ clock-names = "mipi_pllref_clk", "mipi_cfg_clk";
+ status = "disabled";
+ };
+
i2c4: i2c@021f8000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
reg = <0x021f8000 0x4000>;
interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks 116>;
status = "disabled";
};
};
/ {
aliases {
+ ipu1 = &ipu2;
spi4 = &ecspi5;
};
};
soc {
+
+ busfreq { /* BUSFREQ */
+ compatible = "fsl,imx6_busfreq";
+ clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>,
+ <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>;
+ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph",
+ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc";
+ interrupts = <0 107 0x04>, <0 112 0x4>, <0 113 0x4>, <0 114 0x4>;
+ interrupt-names = "irq_busfreq_0", "irq_busfreq_1", "irq_busfreq_2", "irq_busfreq_3";
+ fsl,max_ddr_freq = <528000000>;
+ };
+
+ gpu: gpu@00130000 {
+ compatible = "fsl,imx6q-gpu";
+ reg = <0x00130000 0x4000>, <0x00134000 0x4000>,
+ <0x02204000 0x4000>, <0x0 0x0>;
+ reg-names = "iobase_3d", "iobase_2d",
+ "iobase_vg", "phys_baseaddr";
+ interrupts = <0 9 0x04>, <0 10 0x04>,<0 11 0x04>;
+ interrupt-names = "irq_3d", "irq_2d", "irq_vg";
+ clocks = <&clks 26>, <&clks 143>,
+ <&clks 27>, <&clks 121>,
+ <&clks 122>, <&clks 74>;
+ clock-names = "gpu2d_axi_clk", "openvg_axi_clk",
+ "gpu3d_axi_clk", "gpu2d_clk",
+ "gpu3d_clk", "gpu3d_shader_clk";
+ resets = <&src 0>, <&src 3>, <&src 3>;
+ reset-names = "gpu3d", "gpu2d", "gpuvg";
+ pu-supply = <®_pu>;
+ };
+
ocram: sram@00900000 {
compatible = "mmio-sram";
- reg = <0x00900000 0x40000>;
+ reg = <0x00904000 0x3C000>;
clocks = <&clks 142>;
};
+ hdmi_core: hdmi_core@00120000 {
+ compatible = "fsl,imx6q-hdmi-core";
+ reg = <0x00120000 0x9000>;
+ clocks = <&clks 124>, <&clks 123>;
+ clock-names = "hdmi_isfr", "hdmi_iahb";
+ status = "disabled";
+ };
+
+ hdmi_video: hdmi_video@020e0000 {
+ compatible = "fsl,imx6q-hdmi-video";
+ reg = <0x020e0000 0x1000>;
+ reg-names = "hdmi_gpr";
+ interrupts = <0 115 0x04>;
+ clocks = <&clks 124>, <&clks 123>;
+ clock-names = "hdmi_isfr", "hdmi_iahb";
+ status = "disabled";
+ };
+
+ hdmi_audio: hdmi_audio@00120000 {
+ compatible = "fsl,imx6q-hdmi-audio";
+ clocks = <&clks 124>, <&clks 123>;
+ clock-names = "hdmi_isfr", "hdmi_iahb";
+ dmas = <&sdma 2 22 0>;
+ dma-names = "tx";
+ status = "disabled";
+ };
+
+ hdmi_cec: hdmi_cec@00120000 {
+ compatible = "fsl,imx6q-hdmi-cec";
+ interrupts = <0 115 0x04>;
+ status = "disabled";
+ };
+
+
aips-bus@02000000 { /* AIPS1 */
spba-bus@02000000 {
ecspi5: ecspi@02018000 {
};
};
+ vpu@02040000 {
+ compatible = "fsl,imx6q-vpu";
+ status = "okay";
+ };
+
iomuxc: iomuxc@020e0000 {
compatible = "fsl,imx6q-iomuxc";
+ };
+ };
- ipu2 {
- pinctrl_ipu2_1: ipu2grp-1 {
- fsl,pins = <
- MX6QDL_PAD_DI0_DISP_CLK__IPU2_DI0_DISP_CLK 0x10
- MX6QDL_PAD_DI0_PIN15__IPU2_DI0_PIN15 0x10
- MX6QDL_PAD_DI0_PIN2__IPU2_DI0_PIN02 0x10
- MX6QDL_PAD_DI0_PIN3__IPU2_DI0_PIN03 0x10
- MX6QDL_PAD_DI0_PIN4__IPU2_DI0_PIN04 0x80000000
- MX6QDL_PAD_DISP0_DAT0__IPU2_DISP0_DATA00 0x10
- MX6QDL_PAD_DISP0_DAT1__IPU2_DISP0_DATA01 0x10
- MX6QDL_PAD_DISP0_DAT2__IPU2_DISP0_DATA02 0x10
- MX6QDL_PAD_DISP0_DAT3__IPU2_DISP0_DATA03 0x10
- MX6QDL_PAD_DISP0_DAT4__IPU2_DISP0_DATA04 0x10
- MX6QDL_PAD_DISP0_DAT5__IPU2_DISP0_DATA05 0x10
- MX6QDL_PAD_DISP0_DAT6__IPU2_DISP0_DATA06 0x10
- MX6QDL_PAD_DISP0_DAT7__IPU2_DISP0_DATA07 0x10
- MX6QDL_PAD_DISP0_DAT8__IPU2_DISP0_DATA08 0x10
- MX6QDL_PAD_DISP0_DAT9__IPU2_DISP0_DATA09 0x10
- MX6QDL_PAD_DISP0_DAT10__IPU2_DISP0_DATA10 0x10
- MX6QDL_PAD_DISP0_DAT11__IPU2_DISP0_DATA11 0x10
- MX6QDL_PAD_DISP0_DAT12__IPU2_DISP0_DATA12 0x10
- MX6QDL_PAD_DISP0_DAT13__IPU2_DISP0_DATA13 0x10
- MX6QDL_PAD_DISP0_DAT14__IPU2_DISP0_DATA14 0x10
- MX6QDL_PAD_DISP0_DAT15__IPU2_DISP0_DATA15 0x10
- MX6QDL_PAD_DISP0_DAT16__IPU2_DISP0_DATA16 0x10
- MX6QDL_PAD_DISP0_DAT17__IPU2_DISP0_DATA17 0x10
- MX6QDL_PAD_DISP0_DAT18__IPU2_DISP0_DATA18 0x10
- MX6QDL_PAD_DISP0_DAT19__IPU2_DISP0_DATA19 0x10
- MX6QDL_PAD_DISP0_DAT20__IPU2_DISP0_DATA20 0x10
- MX6QDL_PAD_DISP0_DAT21__IPU2_DISP0_DATA21 0x10
- MX6QDL_PAD_DISP0_DAT22__IPU2_DISP0_DATA22 0x10
- MX6QDL_PAD_DISP0_DAT23__IPU2_DISP0_DATA23 0x10
- >;
- };
- };
+ aips-bus@02100000 { /* AIPS2 */
+ mipi_dsi: mipi@021e0000 {
+ compatible = "fsl,imx6q-mipi-dsi";
+ reg = <0x021e0000 0x4000>;
+ interrupts = <0 102 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 138>, <&clks 204>;
+ clock-names = "mipi_pllref_clk", "mipi_cfg_clk";
+ status = "disabled";
};
};
reg = <0x02800000 0x400000>;
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
<0 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks 133>, <&clks 134>, <&clks 137>;
- clock-names = "bus", "di0", "di1";
+ clocks = <&clks 133>, <&clks 134>, <&clks 137>,
+ <&clks 41>, <&clks 42>,
+ <&clks 135>, <&clks 136>;
+ clock-names = "bus", "di0", "di1",
+ "di0_sel", "di1_sel",
+ "ldb_di0", "ldb_di1";
resets = <&src 4>;
+ bypass_reset = <0>;
ipu2_di0: port@2 {
#address-cells = <1>;
};
&ldb {
- clocks = <&clks 33>, <&clks 34>,
- <&clks 39>, <&clks 40>, <&clks 41>, <&clks 42>,
- <&clks 135>, <&clks 136>;
- clock-names = "di0_pll", "di1_pll",
- "di0_sel", "di1_sel", "di2_sel", "di3_sel",
- "di0", "di1";
-
lvds-channel@0 {
port@2 {
reg = <2>;
mux-int-port = <1>;
mux-ext-port = <5>;
};
+
+ v4l2_out {
+ compatible = "fsl,mxc_v4l2_output";
+ status = "okay";
+ };
};
&audmux {
gpio4 = &gpio5;
gpio5 = &gpio6;
gpio6 = &gpio7;
+ ipu0 = &ipu1;
i2c0 = &i2c1;
i2c1 = &i2c2;
i2c2 = &i2c3;
};
esai: esai@02024000 {
+ compatible = "fsl,imx6q-esai";
reg = <0x02024000 0x4000>;
interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks 118>, <&clks 156>;
+ clock-names = "core", "dma";
+ fsl,esai-dma-events = <24 23>;
+ fsl,flags = <1>;
+ status = "disabled";
};
ssi1: ssi@02028000 {
vpu: vpu@02040000 {
reg = <0x02040000 0x3c000>;
+ reg-names = "vpu_regs";
interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>,
<0 12 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "vpu_jpu_irq", "vpu_ipi_irq";
+ clocks = <&clks 168>, <&clks 140>, <&clks 142>;
+ clock-names = "vpu_clk", "mmdc_ch0_axi", "ocram";
+ iramsize = <0x21000>;
+ iram = <&ocram>;
+ resets = <&src 1>;
+ pu-supply = <®_pu>;
+ status = "disabled";
};
aipstz@0207c000 { /* AIPSTZ1 */
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb";
+ reg = <0x020e0000 0x4000>;
+ clocks = <&clks 135>, <&clks 136>,
+ <&clks 39>, <&clks 40>,
+ <&clks 41>, <&clks 42>,
+ <&clks 184>, <&clks 185>,
+ <&clks 205>, <&clks 206>,
+ <&clks 207>, <&clks 208>;
+ clock-names = "ldb_di0", "ldb_di1",
+ "ipu1_di0_sel", "ipu1_di1_sel",
+ "ipu2_di0_sel", "ipu2_di1_sel",
+ "di0_div_3_5", "di1_div_3_5",
+ "di0_div_7", "di1_div_7",
+ "di0_div_sel", "di1_div_sel";
gpr = <&gpr>;
status = "disabled";
reg = <0x02400000 0x400000>;
interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>,
<0 5 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks 130>, <&clks 131>, <&clks 132>;
- clock-names = "bus", "di0", "di1";
+ clocks = <&clks 130>, <&clks 131>, <&clks 132>,
+ <&clks 39>, <&clks 40>,
+ <&clks 135>, <&clks 136>;
+ clock-names = "bus", "di0", "di1",
+ "di0_sel", "di1_sel",
+ "ldb_di0", "ldb_di1";
resets = <&src 2>;
+ bypass_reset = <0>;
ipu1_di0: port@2 {
#address-cells = <1>;
#endif
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K)
-//# ifdef _CACHE
+# ifdef _CACHE
# define MULTI_CACHE 1
-//# else
-//# define _CACHE v6
-//# endif
+# else
+# define _CACHE v6
+# endif
#endif
#if defined(CONFIG_CPU_V7)
-//# ifdef _CACHE
+# ifdef _CACHE
# define MULTI_CACHE 1
-//# else
-//# define _CACHE v7
-//# endif
+# else
+# define _CACHE v7
+# endif
#endif
#if defined(CONFIG_CPU_V7M)
Be aware that not all cpufreq drivers support the conservative
governor. If unsure have a look at the help section of the
driver. Fallback governor will be the performance governor.
-
-config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
- bool "interactive"
- select CPU_FREQ_GOV_INTERACTIVE
- select CPU_FREQ_GOV_PERFORMANCE
- help
- Use the CPUFreq governor 'interactive' as default. This allows
- you to get a full dynamic cpu frequency capable system by simply
- loading your cpufreq low-level hardware driver, using the
- 'interactive' governor for latency-sensitive workloads. Fallback
- governor will be the performance governor.
-
endchoice
config CPU_FREQ_GOV_PERFORMANCE
If in doubt, say N.
-config CPU_FREQ_GOV_INTERACTIVE
- tristate "'interactive' cpufreq policy governor"
- help
- 'interactive' - This driver adds a dynamic cpufreq policy governor
- designed for latency-sensitive workloads.
-
- This governor attempts to reduce the latency of clock
- increases so that the system is more responsive to
- interactive workloads.
-
- To compile this driver as a module, choose M here: the
- module will be called cpufreq_interactive.
-
- For details, take a look at linux/Documentation/cpu-freq.
-
- If in doubt, say N.
-
config GENERIC_CPUFREQ_CPU0
tristate "Generic CPU0 cpufreq driver"
depends on HAVE_CLK && OF
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
-obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o
obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o
+++ /dev/null
-/*
- * drivers/cpufreq/cpufreq_interactive.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2012-2013 Freescale Semiconductor, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- * Author: Mike Chan (mike@android.com)
- *
- */
-
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
-#include <linux/cpufreq.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/tick.h>
-#include <linux/time.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <asm/cputime.h>
-
-static atomic_t active_count = ATOMIC_INIT(0);
-
-struct cpufreq_interactive_cpuinfo {
- struct timer_list cpu_timer;
- int timer_idlecancel;
- u64 time_in_idle;
- u64 idle_exit_time;
- u64 timer_run_time;
- int idling;
- u64 freq_change_time;
- u64 freq_change_time_in_idle;
- struct cpufreq_policy *policy;
- struct cpufreq_frequency_table *freq_table;
- unsigned int target_freq;
- int governor_enabled;
-};
-
-static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo);
-
-/* Workqueues handle frequency scaling */
-static struct task_struct *up_task;
-static struct workqueue_struct *down_wq;
-static struct work_struct freq_scale_down_work;
-static cpumask_t up_cpumask;
-static spinlock_t up_cpumask_lock;
-static cpumask_t down_cpumask;
-static spinlock_t down_cpumask_lock;
-static struct mutex set_speed_lock;
-
-/* Hi speed to bump to from lo speed when load burst (default max) */
-static u64 hispeed_freq;
-
-/* Go to hi speed when CPU load at or above this value. */
-#define DEFAULT_GO_HISPEED_LOAD 95
-static unsigned long go_hispeed_load;
-
-/*
- * The minimum amount of time to spend at a frequency before we can ramp down.
- */
-#define DEFAULT_MIN_SAMPLE_TIME (20 * USEC_PER_MSEC)
-static unsigned long min_sample_time;
-
-/*
- * The sample rate of the timer used to increase frequency
- */
-#define DEFAULT_TIMER_RATE (50 * USEC_PER_MSEC)
-#define CPUFREQ_IRQ_LEN 60
-#define CPUFREQ_NOTE_LEN 120
-static unsigned long timer_rate;
-
-static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
- unsigned int event);
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
-static
-#endif
-struct cpufreq_governor cpufreq_gov_interactive = {
- .name = "interactive",
- .governor = cpufreq_governor_interactive,
- .max_transition_latency = 10000000,
- .owner = THIS_MODULE,
-};
-
-static void cpufreq_interactive_timer(unsigned long data)
-{
- unsigned int delta_idle;
- unsigned int delta_time;
- int cpu_load;
- int load_since_change;
- u64 time_in_idle;
- u64 idle_exit_time;
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, data);
- u64 now_idle;
- unsigned int new_freq;
- unsigned int index;
- unsigned long flags;
-
- smp_rmb();
-
- if (!pcpu->governor_enabled)
- goto exit;
-
- /*
- * Once pcpu->timer_run_time is updated to >= pcpu->idle_exit_time,
- * this lets idle exit know the current idle time sample has
- * been processed, and idle exit can generate a new sample and
- * re-arm the timer. This prevents a concurrent idle
- * exit on that CPU from writing a new set of info at the same time
- * the timer function runs (the timer function can't use that info
- * until more time passes).
- */
- time_in_idle = pcpu->time_in_idle;
- idle_exit_time = pcpu->idle_exit_time;
- now_idle = get_cpu_idle_time_us(data, &pcpu->timer_run_time);
- smp_wmb();
-
- /* If we raced with cancelling a timer, skip. */
- if (!idle_exit_time)
- goto exit;
-
- delta_idle = (unsigned int)(now_idle - time_in_idle);
- delta_time = (unsigned int)(pcpu->timer_run_time - idle_exit_time);
-
- /*
- * If timer ran less than 1ms after short-term sample started, retry.
- */
- if (delta_time < 1000)
- goto rearm;
-
- if (delta_idle > delta_time)
- cpu_load = 0;
- else
- cpu_load = 100 * (delta_time - delta_idle) / delta_time;
-
- delta_idle = (unsigned int)(now_idle - pcpu->freq_change_time_in_idle);
- delta_time = (unsigned int)(pcpu->timer_run_time -
- pcpu->freq_change_time);
-
- if ((delta_time == 0) || (delta_idle > delta_time))
- load_since_change = 0;
- else
- load_since_change =
- 100 * (delta_time - delta_idle) / delta_time;
-
- /*
- * Choose greater of short-term load (since last idle timer
- * started or timer function re-armed itself) or long-term load
- * (since last frequency change).
- */
- if (load_since_change > cpu_load)
- cpu_load = load_since_change;
-
- if (cpu_load >= go_hispeed_load) {
- if (pcpu->policy->cur == pcpu->policy->min)
- new_freq = hispeed_freq;
- else
- new_freq = pcpu->policy->max * cpu_load / 100;
- } else {
- new_freq = pcpu->policy->cur * cpu_load / 100;
- }
-
- if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
- new_freq, CPUFREQ_RELATION_H,
- &index)) {
- pr_warn_once("timer %d: cpufreq_frequency_table_target error\n",
- (int) data);
- goto rearm;
- }
-
- new_freq = pcpu->freq_table[index].frequency;
- if (pcpu->target_freq == new_freq)
- goto rearm_if_notmax;
-
- /*
- * Do not scale down unless we have been at this frequency for the
- * minimum sample time.
- */
- if (new_freq < pcpu->target_freq) {
- if ((pcpu->timer_run_time - pcpu->freq_change_time)
- < min_sample_time)
- goto rearm;
- }
-
- if (new_freq < pcpu->target_freq) {
- pcpu->target_freq = new_freq;
- spin_lock_irqsave(&down_cpumask_lock, flags);
- cpumask_set_cpu(data, &down_cpumask);
- spin_unlock_irqrestore(&down_cpumask_lock, flags);
- queue_work(down_wq, &freq_scale_down_work);
- } else {
- pcpu->target_freq = new_freq;
- spin_lock_irqsave(&up_cpumask_lock, flags);
- cpumask_set_cpu(data, &up_cpumask);
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
- wake_up_process(up_task);
- }
-
-rearm_if_notmax:
- /*
- * Already set max speed and don't see a need to change that,
- * wait until next idle to re-evaluate, don't need timer.
- */
- if (pcpu->target_freq == pcpu->policy->max)
- goto exit;
-
-rearm:
- if (!timer_pending(&pcpu->cpu_timer)) {
- /*
- * If already at min: if that CPU is idle, don't set timer.
- * Else cancel the timer if that CPU goes idle. We don't
- * need to re-evaluate speed until the next idle exit.
- */
- if (pcpu->target_freq == pcpu->policy->min) {
- smp_rmb();
-
- if (pcpu->idling)
- goto exit;
-
- pcpu->timer_idlecancel = 1;
- }
-
- pcpu->time_in_idle = get_cpu_idle_time_us(
- data, &pcpu->idle_exit_time);
- mod_timer(&pcpu->cpu_timer,
- jiffies + usecs_to_jiffies(timer_rate));
- }
-
-exit:
- return;
-}
-
-static void cpufreq_interactive_idle_start(void)
-{
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, smp_processor_id());
- int pending;
-
- pcpu->idling = 1;
- smp_wmb();
- if (!pcpu->governor_enabled)
- return;
- pending = timer_pending(&pcpu->cpu_timer);
-
- if (pcpu->target_freq != pcpu->policy->min) {
-#ifdef CONFIG_SMP
- /*
- * Entering idle while not at lowest speed. On some
- * platforms this can hold the other CPU(s) at that speed
- * even though the CPU is idle. Set a timer to re-evaluate
- * speed so this idle CPU doesn't hold the other CPUs above
- * min indefinitely. This should probably be a quirk of
- * the CPUFreq driver.
- */
- if (!pending) {
- pcpu->time_in_idle = get_cpu_idle_time_us(
- smp_processor_id(), &pcpu->idle_exit_time);
- pcpu->timer_idlecancel = 0;
- mod_timer(&pcpu->cpu_timer,
- jiffies + usecs_to_jiffies(timer_rate));
- }
-#endif
- } else {
- /*
- * If at min speed and entering idle after load has
- * already been evaluated, and a timer has been set just in
- * case the CPU suddenly goes busy, cancel that timer. The
- * CPU didn't go busy; we'll recheck things upon idle exit.
- */
- if (pending && pcpu->timer_idlecancel) {
- del_timer(&pcpu->cpu_timer);
- /*
- * Ensure last timer run time is after current idle
- * sample start time, so next idle exit will always
- * start a new idle sampling period.
- */
- pcpu->idle_exit_time = 0;
- pcpu->timer_idlecancel = 0;
- }
- }
-
-}
-
-static void cpufreq_interactive_idle_end(void)
-{
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, smp_processor_id());
-
- pcpu->idling = 0;
- smp_wmb();
-
- /*
- * Arm the timer for 1-2 ticks later if not already, and if the timer
- * function has already processed the previous load sampling
- * interval. (If the timer is not pending but has not processed
- * the previous interval, it is probably racing with us on another
- * CPU. Let it compute load based on the previous sample and then
- * re-arm the timer for another interval when it's done, rather
- * than updating the interval start time to be "now", which doesn't
- * give the timer function enough time to make a decision on this
- * run.)
- */
- if (timer_pending(&pcpu->cpu_timer) == 0 &&
- pcpu->timer_run_time >= pcpu->idle_exit_time &&
- pcpu->governor_enabled) {
- pcpu->time_in_idle =
- get_cpu_idle_time_us(smp_processor_id(),
- &pcpu->idle_exit_time);
- pcpu->timer_idlecancel = 0;
- mod_timer(&pcpu->cpu_timer,
- jiffies + usecs_to_jiffies(timer_rate));
- }
-
-}
-
-static int cpufreq_interactive_up_task(void *data)
-{
- unsigned int cpu;
- unsigned long flags;
- struct cpufreq_interactive_cpuinfo *pcpu;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&up_cpumask_lock, flags);
-
- if (cpumask_empty(&up_cpumask)) {
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
- schedule();
-
- if (kthread_should_stop())
- break;
-
- spin_lock_irqsave(&up_cpumask_lock, flags);
- }
-
- set_current_state(TASK_RUNNING);
- cpumask_clear(&up_cpumask);
- spin_unlock_irqrestore(&up_cpumask_lock, flags);
-
- for_each_online_cpu(cpu) {
- unsigned int j;
- unsigned int max_freq = 0;
-
- pcpu = &per_cpu(cpuinfo, cpu);
- smp_rmb();
-
- if (!pcpu->governor_enabled)
- continue;
-
- mutex_lock(&set_speed_lock);
-
- for_each_online_cpu(j) {
- struct cpufreq_interactive_cpuinfo *pjcpu =
- &per_cpu(cpuinfo, j);
- if (pjcpu->target_freq > max_freq)
- max_freq = pjcpu->target_freq;
- }
- if (max_freq != pcpu->policy->cur)
- __cpufreq_driver_target(pcpu->policy,
- max_freq,
- CPUFREQ_RELATION_H);
- mutex_unlock(&set_speed_lock);
-
- pcpu->freq_change_time_in_idle =
- get_cpu_idle_time_us(cpu,
- &pcpu->freq_change_time);
- }
- }
-
- return 0;
-}
-
-static void cpufreq_interactive_freq_down(struct work_struct *work)
-{
- unsigned int cpu;
- unsigned long flags;
- struct cpufreq_interactive_cpuinfo *pcpu;
-
- spin_lock_irqsave(&down_cpumask_lock, flags);
- cpumask_clear(&down_cpumask);
- spin_unlock_irqrestore(&down_cpumask_lock, flags);
-
- for_each_online_cpu(cpu) {
- unsigned int j;
- unsigned int max_freq = 0;
-
- pcpu = &per_cpu(cpuinfo, cpu);
- smp_rmb();
-
- if (!pcpu->governor_enabled)
- continue;
-
- mutex_lock(&set_speed_lock);
-
- for_each_online_cpu(j) {
- struct cpufreq_interactive_cpuinfo *pjcpu =
- &per_cpu(cpuinfo, j);
-
- if (pjcpu->target_freq > max_freq)
- max_freq = pjcpu->target_freq;
- }
-
- if (max_freq != pcpu->policy->cur)
- __cpufreq_driver_target(pcpu->policy, max_freq,
- CPUFREQ_RELATION_H);
-
- mutex_unlock(&set_speed_lock);
- pcpu->freq_change_time_in_idle =
- get_cpu_idle_time_us(cpu,
- &pcpu->freq_change_time);
- }
-}
-
-static ssize_t show_hispeed_freq(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%llu\n", hispeed_freq);
-}
-
-static ssize_t store_hispeed_freq(struct kobject *kobj,
- struct attribute *attr, const char *buf,
- size_t count)
-{
- int ret;
- u64 val;
-
- ret = strict_strtoull(buf, 0, &val);
- if (ret < 0)
- return ret;
- hispeed_freq = val;
- return count;
-}
-
-static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644,
- show_hispeed_freq, store_hispeed_freq);
-
-
-static ssize_t show_go_hispeed_load(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", go_hispeed_load);
-}
-
-static ssize_t store_go_hispeed_load(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- go_hispeed_load = val;
- return count;
-}
-
-static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644,
- show_go_hispeed_load, store_go_hispeed_load);
-
-static ssize_t show_min_sample_time(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", min_sample_time);
-}
-
-static ssize_t store_min_sample_time(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- min_sample_time = val;
- return count;
-}
-
-static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644,
- show_min_sample_time, store_min_sample_time);
-
-static ssize_t show_timer_rate(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", timer_rate);
-}
-
-static ssize_t store_timer_rate(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- int ret;
- unsigned long val;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- timer_rate = val;
- return count;
-}
-
-static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644,
- show_timer_rate, store_timer_rate);
-
-static struct attribute *interactive_attributes[] = {
- &hispeed_freq_attr.attr,
- &go_hispeed_load_attr.attr,
- &min_sample_time_attr.attr,
- &timer_rate_attr.attr,
- NULL,
-};
-
-static struct attribute_group interactive_attr_group = {
- .attrs = interactive_attributes,
- .name = "interactive",
-};
-
-static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
- unsigned int event)
-{
- int rc;
- unsigned int j;
- struct cpufreq_interactive_cpuinfo *pcpu;
- struct cpufreq_frequency_table *freq_table;
-
- switch (event) {
- case CPUFREQ_GOV_START:
- if (!cpu_online(policy->cpu))
- return -EINVAL;
-
- freq_table =
- cpufreq_frequency_get_table(policy->cpu);
-
- for_each_cpu(j, policy->cpus) {
- pcpu = &per_cpu(cpuinfo, j);
- pcpu->policy = policy;
- if (pcpu->idling)
- pcpu->target_freq = policy->min;
- else
- pcpu->target_freq = policy->cur;
-
- pcpu->freq_table = freq_table;
- pcpu->freq_change_time_in_idle =
- get_cpu_idle_time_us(j,
- &pcpu->freq_change_time);
- pcpu->governor_enabled = 1;
- smp_wmb();
- }
-
- if (!hispeed_freq)
- hispeed_freq = policy->max;
-
- /*
- * Do not register the idle hook and create sysfs
- * entries if we have already done so.
- */
- if (atomic_inc_return(&active_count) > 1)
- return 0;
-
- rc = sysfs_create_group(cpufreq_global_kobject,
- &interactive_attr_group);
- if (rc)
- return rc;
-
- break;
-
- case CPUFREQ_GOV_STOP:
- for_each_cpu(j, policy->cpus) {
- pcpu = &per_cpu(cpuinfo, j);
- pcpu->governor_enabled = 0;
- smp_wmb();
- del_timer_sync(&pcpu->cpu_timer);
-
- /*
- * Reset idle exit time since we may cancel the timer
- * before it can run after the last idle exit time,
- * to avoid tripping the check in idle exit for a timer
- * that is trying to run.
- */
- pcpu->idle_exit_time = 0;
- }
-
- flush_work(&freq_scale_down_work);
- if (atomic_dec_return(&active_count) > 0)
- return 0;
-
- sysfs_remove_group(cpufreq_global_kobject,
- &interactive_attr_group);
-
- break;
-
- case CPUFREQ_GOV_LIMITS:
- if (policy->max < policy->cur)
- __cpufreq_driver_target(policy,
- policy->max, CPUFREQ_RELATION_H);
- else if (policy->min > policy->cur)
- __cpufreq_driver_target(policy,
- policy->min, CPUFREQ_RELATION_L);
- break;
- }
- return 0;
-}
-
-static int cpufreq_interactive_idle_notifier(struct notifier_block *nb,
- unsigned long val,
- void *data)
-{
- switch (val) {
- case IDLE_START:
- cpufreq_interactive_idle_start();
- break;
- case IDLE_END:
- cpufreq_interactive_idle_end();
- break;
- }
-
- return 0;
-}
-
-static struct notifier_block cpufreq_interactive_idle_nb = {
- .notifier_call = cpufreq_interactive_idle_notifier,
-};
-
-static int __init cpufreq_interactive_init(void)
-{
- unsigned int i;
- struct cpufreq_interactive_cpuinfo *pcpu;
- struct sched_param param = { .sched_priority = 99 };
-
- go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
- min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
- timer_rate = DEFAULT_TIMER_RATE;
-
- /* Initalize per-cpu timers */
- for_each_possible_cpu(i) {
- pcpu = &per_cpu(cpuinfo, i);
- init_timer(&pcpu->cpu_timer);
- pcpu->cpu_timer.function = cpufreq_interactive_timer;
- pcpu->cpu_timer.data = i;
- }
-
- up_task = kthread_create(cpufreq_interactive_up_task, NULL,
- "kinteractiveup");
- if (IS_ERR(up_task))
- return PTR_ERR(up_task);
-
- sched_setscheduler_nocheck(up_task, SCHED_FIFO, ¶m);
- get_task_struct(up_task);
-
- /* No rescuer thread, bind to CPU queuing the work for possibly
- warm cache (probably doesn't matter much). */
- down_wq = alloc_workqueue("kinteractive_down", 0, 1);
-
- if (!down_wq)
- goto err_freeuptask;
-
- INIT_WORK(&freq_scale_down_work,
- cpufreq_interactive_freq_down);
-
- spin_lock_init(&up_cpumask_lock);
- spin_lock_init(&down_cpumask_lock);
- mutex_init(&set_speed_lock);
-
- idle_notifier_register(&cpufreq_interactive_idle_nb);
-
- return cpufreq_register_governor(&cpufreq_gov_interactive);
-
-err_freeuptask:
- put_task_struct(up_task);
- return -ENOMEM;
-}
-
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
-late_initcall(cpufreq_interactive_init);
-#else
-module_init(cpufreq_interactive_init);
-#endif
-
-static void __exit cpufreq_interactive_exit(void)
-{
- cpufreq_unregister_governor(&cpufreq_gov_interactive);
- kthread_stop(up_task);
- put_task_struct(up_task);
- destroy_workqueue(down_wq);
-}
-
-module_exit(cpufreq_interactive_exit);
-
-MODULE_AUTHOR("Mike Chan <mike@android.com>");
-MODULE_DESCRIPTION("'cpufreq_interactive' - A cpufreq governor for "
- "Latency sensitive workloads");
-MODULE_LICENSE("GPL");
emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
break;
case IMX_DMATYPE_ASRC:
- per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
- emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
+ per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
per_2_per = sdma->script_addrs->per_2_per_addr;
break;
case IMX_DMATYPE_MSHC:
-##############################################################################
-#
-# Copyright (C) 2005 - 2013 by Vivante Corp.
-#
-# 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.
-#
-##############################################################################
-
-
#
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
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.
-
-config MXC_MMA8451
- tristate "MMA8451 device driver"
- depends on I2C
- default y
-
endif # HWMON
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
-obj-$(CONFIG_SENSORS_MAG3110) += mag3110.o
-obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o
obj-$(CONFIG_PMBUS) += pmbus/
+++ /dev/null
-/*
- *
- * Copyright (C) 2011-2013 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/input-polldev.h>
-#include <linux/hwmon.h>
-#include <linux/input.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-#include <linux/regulator/consumer.h>
-
-#define MAG3110_DRV_NAME "mag3110"
-#define MAG3110_ID 0xC4
-#define MAG3110_XYZ_DATA_LEN 6
-#define MAG3110_STATUS_ZYXDR 0x08
-
-#define MAG3110_AC_MASK (0x01)
-#define MAG3110_AC_OFFSET 0
-#define MAG3110_DR_MODE_MASK (0x7 << 5)
-#define MAG3110_DR_MODE_OFFSET 5
-#define MAG3110_IRQ_USED 0
-
-#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;
-/*!
- * This function do one mag3110 register read.
- */
-static DEFINE_MUTEX(mag3110_lock);
-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;
- int retry = 3;
- u8 tmp_data[MAG3110_XYZ_DATA_LEN];
- int result;
- 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;
-
- 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)
-{
- mag3110_pdata->data_ready = 1;
- 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 = strict_strtol(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;
- }
-
- if (mag3110_pdata->active == MAG_ACTIVED) {
- msleep(100);
- /* Read out MSB data to clear interrupt flag automatically */
- mag3110_read_block_data(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 ((strict_strtoul(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 = strict_strtol(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;
- 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;
- }
- /* set irq type to edge rising */
-#if MAG3110_IRQ_USED
- ret = request_irq(client->irq, mag3110_irq_handler,
- IRQF_TRIGGER_RISING, 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 i2c_client *client, pm_message_t mesg)
-{
- int ret = 0;
- 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 i2c_client *client)
-{
- int ret = 0;
- u8 tmp_data[MAG3110_XYZ_DATA_LEN];
- struct mag3110_data *data = i2c_get_clientdata(client);
- 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;
-}
-
-#else
-#define mag3110_suspend NULL
-#define mag3110_resume 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,},
- .suspend = mag3110_suspend,
- .resume = mag3110_resume,
- .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");
+++ /dev/null
-/*
- * mma8451.c - Linux kernel modules for 3-Axis Orientation/Motion
- * Detection Sensor
- *
- * Copyright (C) 2010-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 <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/pm.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/hwmon.h>
-#include <linux/input-polldev.h>
-#include <linux/of.h>
-#include <linux/regulator/consumer.h>
-
-#define MMA8451_I2C_ADDR 0x1C
-#define MMA8451_ID 0x1A
-#define MMA8452_ID 0x2A
-#define MMA8453_ID 0x3A
-
-#define POLL_INTERVAL_MIN 1
-#define POLL_INTERVAL_MAX 500
-#define POLL_INTERVAL 100 /* msecs */
-#define INPUT_FUZZ 32
-#define INPUT_FLAT 32
-#define MODE_CHANGE_DELAY_MS 100
-
-#define MMA8451_STATUS_ZYXDR 0x08
-#define MMA8451_BUF_SIZE 7
-#define DEFAULT_POSITION 0
-
-/* register enum for mma8451 registers */
-enum {
- MMA8451_STATUS = 0x00,
- MMA8451_OUT_X_MSB,
- MMA8451_OUT_X_LSB,
- MMA8451_OUT_Y_MSB,
- MMA8451_OUT_Y_LSB,
- MMA8451_OUT_Z_MSB,
- MMA8451_OUT_Z_LSB,
-
- MMA8451_F_SETUP = 0x09,
- MMA8451_TRIG_CFG,
- MMA8451_SYSMOD,
- MMA8451_INT_SOURCE,
- MMA8451_WHO_AM_I,
- MMA8451_XYZ_DATA_CFG,
- MMA8451_HP_FILTER_CUTOFF,
-
- MMA8451_PL_STATUS,
- MMA8451_PL_CFG,
- MMA8451_PL_COUNT,
- MMA8451_PL_BF_ZCOMP,
- MMA8451_P_L_THS_REG,
-
- MMA8451_FF_MT_CFG,
- MMA8451_FF_MT_SRC,
- MMA8451_FF_MT_THS,
- MMA8451_FF_MT_COUNT,
-
- MMA8451_TRANSIENT_CFG = 0x1D,
- MMA8451_TRANSIENT_SRC,
- MMA8451_TRANSIENT_THS,
- MMA8451_TRANSIENT_COUNT,
-
- MMA8451_PULSE_CFG,
- MMA8451_PULSE_SRC,
- MMA8451_PULSE_THSX,
- MMA8451_PULSE_THSY,
- MMA8451_PULSE_THSZ,
- MMA8451_PULSE_TMLT,
- MMA8451_PULSE_LTCY,
- MMA8451_PULSE_WIND,
-
- MMA8451_ASLP_COUNT,
- MMA8451_CTRL_REG1,
- MMA8451_CTRL_REG2,
- MMA8451_CTRL_REG3,
- MMA8451_CTRL_REG4,
- MMA8451_CTRL_REG5,
-
- MMA8451_OFF_X,
- MMA8451_OFF_Y,
- MMA8451_OFF_Z,
-
- MMA8451_REG_END,
-};
-
-/* The sensitivity is represented in counts/g. In 2g mode the
-sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512
-counts/g and in 8g mode the sensitivity is 256 counts/g.
- */
-enum {
- MODE_2G = 0,
- MODE_4G,
- MODE_8G,
-};
-
-enum {
- MMA_STANDBY = 0,
- MMA_ACTIVED,
-};
-
-/* mma8451 status */
-struct mma8451_status {
- u8 mode;
- u8 ctl_reg1;
- int active;
- int position;
-};
-
-static struct mma8451_status mma_status;
-static struct input_polled_dev *mma8451_idev;
-static struct device *hwmon_dev;
-static struct i2c_client *mma8451_i2c_client;
-
-static int senstive_mode = MODE_2G;
-static int ACCHAL[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 DEFINE_MUTEX(mma8451_lock);
-static int mma8451_adjust_position(short *x, short *y, short *z)
-{
- short rawdata[3], data[3];
- int i, j;
- int position = mma_status.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] * ACCHAL[position][i][j];
- }
- *x = data[0];
- *y = data[1];
- *z = data[2];
- return 0;
-}
-
-static int mma8451_change_mode(struct i2c_client *client, int mode)
-{
- int result;
-
- mma_status.ctl_reg1 = 0;
- result = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, 0);
- if (result < 0)
- goto out;
- mma_status.active = MMA_STANDBY;
-
- result = i2c_smbus_write_byte_data(client, MMA8451_XYZ_DATA_CFG,
- mode);
- if (result < 0)
- goto out;
- mdelay(MODE_CHANGE_DELAY_MS);
- mma_status.mode = mode;
-
- return 0;
-out:
- dev_err(&client->dev, "error when init mma8451:(%d)", result);
- return result;
-}
-
-static int mma8451_read_data(short *x, short *y, short *z)
-{
- u8 tmp_data[MMA8451_BUF_SIZE];
- int ret;
-
- ret = i2c_smbus_read_i2c_block_data(mma8451_i2c_client,
- MMA8451_OUT_X_MSB, 7, tmp_data);
- if (ret < MMA8451_BUF_SIZE) {
- dev_err(&mma8451_i2c_client->dev, "i2c block read failed\n");
- return -EIO;
- }
-
- *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)
-{
- short x, y, z;
- int result;
- int retry = 3;
-
- mutex_lock(&mma8451_lock);
- if (mma_status.active == MMA_STANDBY)
- goto out;
- /* wait for the data ready */
- do {
- result = i2c_smbus_read_byte_data(mma8451_i2c_client,
- MMA8451_STATUS);
- retry--;
- msleep(1);
- } while (!(result & MMA8451_STATUS_ZYXDR) && retry > 0);
- if (retry == 0)
- goto out;
- if (mma8451_read_data(&x, &y, &z) != 0)
- goto out;
- mma8451_adjust_position(&x, &y, &z);
- input_report_abs(mma8451_idev->input, ABS_X, x);
- input_report_abs(mma8451_idev->input, ABS_Y, y);
- input_report_abs(mma8451_idev->input, ABS_Z, z);
- input_sync(mma8451_idev->input);
-out:
- mutex_unlock(&mma8451_lock);
-}
-
-static void mma8451_dev_poll(struct input_polled_dev *dev)
-{
- report_abs();
-}
-
-static ssize_t mma8451_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i2c_client *client;
- u8 val;
- int enable;
-
- mutex_lock(&mma8451_lock);
- client = mma8451_i2c_client;
- val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
- if ((val & 0x01) && mma_status.active == MMA_ACTIVED)
- enable = 1;
- else
- enable = 0;
- mutex_unlock(&mma8451_lock);
- return sprintf(buf, "%d\n", enable);
-}
-
-static ssize_t mma8451_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct i2c_client *client;
- int ret;
- unsigned long enable;
- u8 val = 0;
-
- ret = strict_strtoul(buf, 10, &enable);
- if (ret) {
- dev_err(dev, "string transform error\n");
- return ret;
- }
-
- mutex_lock(&mma8451_lock);
- client = mma8451_i2c_client;
- enable = (enable > 0) ? 1 : 0;
- if (enable && mma_status.active == MMA_STANDBY) {
- val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
- ret =
- i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
- val | 0x01);
- if (!ret)
- mma_status.active = MMA_ACTIVED;
-
- } else if (enable == 0 && mma_status.active == MMA_ACTIVED) {
- val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
- ret =
- i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
- val & 0xFE);
- if (!ret)
- mma_status.active = MMA_STANDBY;
-
- }
- mutex_unlock(&mma8451_lock);
- return count;
-}
-
-static ssize_t mma8451_position_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int position = 0;
- mutex_lock(&mma8451_lock);
- position = mma_status.position;
- mutex_unlock(&mma8451_lock);
- return sprintf(buf, "%d\n", position);
-}
-
-static ssize_t mma8451_position_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned long position;
- int ret;
- ret = strict_strtoul(buf, 10, &position);
- if (ret) {
- dev_err(dev, "string transform error\n");
- return ret;
- }
-
- mutex_lock(&mma8451_lock);
- mma_status.position = (int)position;
- mutex_unlock(&mma8451_lock);
- return count;
-}
-
-static ssize_t mma8451_scalemode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- int mode = 0;
- mutex_lock(&mma8451_lock);
- mode = (int)mma_status.mode;
- mutex_unlock(&mma8451_lock);
-
- return sprintf(buf, "%d\n", mode);
-}
-
-static ssize_t mma8451_scalemode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned long mode;
- int ret, active_save;
- struct i2c_client *client = mma8451_i2c_client;
-
- ret = strict_strtoul(buf, 10, &mode);
- if (ret) {
- dev_err(dev, "string transform error\n");
- goto out;
- }
-
- if (mode > MODE_8G) {
- dev_warn(dev, "not supported mode\n");
- ret = count;
- goto out;
- }
-
- mutex_lock(&mma8451_lock);
- if (mode == mma_status.mode) {
- ret = count;
- goto out_unlock;
- }
-
- active_save = mma_status.active;
- ret = mma8451_change_mode(client, mode);
- if (ret)
- goto out_unlock;
-
- if (active_save == MMA_ACTIVED) {
- ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, 1);
-
- if (ret)
- goto out_unlock;
- mma_status.active = active_save;
- }
-
-out_unlock:
- mutex_unlock(&mma8451_lock);
-out:
- return ret;
-}
-
-static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
- mma8451_enable_show, mma8451_enable_store);
-static DEVICE_ATTR(position, S_IWUSR | S_IRUGO,
- mma8451_position_show, mma8451_position_store);
-static DEVICE_ATTR(scalemode, S_IWUSR | S_IRUGO,
- mma8451_scalemode_show, mma8451_scalemode_store);
-
-static struct attribute *mma8451_attributes[] = {
- &dev_attr_enable.attr,
- &dev_attr_position.attr,
- &dev_attr_scalemode.attr,
- NULL
-};
-
-static const struct attribute_group mma8451_attr_group = {
- .attrs = mma8451_attributes,
-};
-
-static int mma8451_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int result, client_id;
- struct input_dev *idev;
- struct i2c_adapter *adapter;
- u32 pos;
- struct device_node *of_node = client->dev.of_node;
- struct regulator *vdd, *vdd_io;
-
- mma8451_i2c_client = client;
-
- vdd = devm_regulator_get(&client->dev, "vdd");
- if (!IS_ERR(vdd)) {
- result = regulator_enable(vdd);
- if (result) {
- dev_err(&client->dev, "vdd set voltage error\n");
- return result;
- }
- }
-
- vdd_io = devm_regulator_get(&client->dev, "vddio");
- if (!IS_ERR(vdd_io)) {
- result = regulator_enable(vdd_io);
- if (result) {
- dev_err(&client->dev, "vddio set voltage error\n");
- return result;
- }
- }
-
- 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, MMA8451_WHO_AM_I);
- if (client_id != MMA8451_ID && client_id != MMA8452_ID
- && client_id != MMA8453_ID) {
- dev_err(&client->dev,
- "read chip ID 0x%x is not equal to 0x%x or 0x%x!\n",
- result, MMA8451_ID, MMA8452_ID);
- result = -EINVAL;
- goto err_out;
- }
-
- /* Initialize the MMA8451 chip */
- result = mma8451_change_mode(client, senstive_mode);
- if (result) {
- dev_err(&client->dev,
- "error when init mma8451 chip:(%d)\n", result);
- goto err_out;
- }
-
- hwmon_dev = hwmon_device_register(&client->dev);
- if (!hwmon_dev) {
- result = -ENOMEM;
- dev_err(&client->dev, "error when register hwmon device\n");
- goto err_out;
- }
-
- mma8451_idev = input_allocate_polled_device();
- if (!mma8451_idev) {
- result = -ENOMEM;
- dev_err(&client->dev, "alloc poll device failed!\n");
- goto err_alloc_poll_device;
- }
- mma8451_idev->poll = mma8451_dev_poll;
- mma8451_idev->poll_interval = POLL_INTERVAL;
- mma8451_idev->poll_interval_min = POLL_INTERVAL_MIN;
- mma8451_idev->poll_interval_max = POLL_INTERVAL_MAX;
- idev = mma8451_idev->input;
- idev->name = "mma845x";
- idev->id.bustype = BUS_I2C;
- idev->evbit[0] = BIT_MASK(EV_ABS);
-
- input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
- input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
- input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
-
- result = input_register_polled_device(mma8451_idev);
- if (result) {
- dev_err(&client->dev, "register poll device failed!\n");
- goto err_register_polled_device;
- }
- result = sysfs_create_group(&idev->dev.kobj, &mma8451_attr_group);
- if (result) {
- dev_err(&client->dev, "create device file failed!\n");
- result = -EINVAL;
- goto err_register_polled_device;
- }
-
- result = of_property_read_u32(of_node, "position", &pos);
- if (result)
- pos = DEFAULT_POSITION;
- mma_status.position = (int)pos;
-
- return 0;
-err_register_polled_device:
- input_free_polled_device(mma8451_idev);
-err_alloc_poll_device:
- hwmon_device_unregister(&client->dev);
-err_out:
- return result;
-}
-
-static int mma8451_stop_chip(struct i2c_client *client)
-{
- int ret = 0;
- if (mma_status.active == MMA_ACTIVED) {
- mma_status.ctl_reg1 = i2c_smbus_read_byte_data(client,
- MMA8451_CTRL_REG1);
- ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
- mma_status.ctl_reg1 & 0xFE);
- }
- return ret;
-}
-
-static int mma8451_remove(struct i2c_client *client)
-{
- int ret;
- ret = mma8451_stop_chip(client);
- hwmon_device_unregister(hwmon_dev);
-
- return ret;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int mma8451_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
-
- return mma8451_stop_chip(client);
-}
-
-static int mma8451_resume(struct device *dev)
-{
- int ret = 0;
- struct i2c_client *client = to_i2c_client(dev);
- if (mma_status.active == MMA_ACTIVED)
- ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
- mma_status.ctl_reg1);
- return ret;
-
-}
-#endif
-
-static const struct i2c_device_id mma8451_id[] = {
- {"mma8451", 0},
-};
-
-MODULE_DEVICE_TABLE(i2c, mma8451_id);
-
-static SIMPLE_DEV_PM_OPS(mma8451_pm_ops, mma8451_suspend, mma8451_resume);
-static struct i2c_driver mma8451_driver = {
- .driver = {
- .name = "mma8451",
- .owner = THIS_MODULE,
- .pm = &mma8451_pm_ops,
- },
- .probe = mma8451_probe,
- .remove = mma8451_remove,
- .id_table = mma8451_id,
-};
-
-static int __init mma8451_init(void)
-{
- /* register driver */
- int res;
-
- res = i2c_add_driver(&mma8451_driver);
- if (res < 0) {
- printk(KERN_INFO "add mma8451 i2c driver failed\n");
- return -ENODEV;
- }
- return res;
-}
-
-static void __exit mma8451_exit(void)
-{
- i2c_del_driver(&mma8451_driver);
-}
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("MMA8451 3-Axis Orientation/Motion Detection Sensor driver");
-MODULE_LICENSE("GPL");
-
-module_init(mma8451_init);
-module_exit(mma8451_exit);
To compile this driver as a module, choose M here: the
module will be called egalax_ts.
-config TOUCHSCREEN_EGALAX_SINGLE_TOUCH
- bool "EETI eGalax touchscreen as single-touch"
- default N
- depends on TOUCHSCREEN_EGALAX
- help
- If you say yes here you get single-touch touchscreen support
- on the eGalax I2C controller.
- If you say "no", you'll get the normal multi-touch
-
-config TOUCHSCREEN_ELAN
- tristate "ELAN touchscreen input driver"
- depends on I2C
- help
- Say Y here if you have an I2C ELAN touchscreen
- attached.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called elan-touch.
-
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
-obj-$(CONFIG_TOUCHSCREEN_ELAN) += elan_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
/*
* Driver for EETI eGalax Multiple Touch Controller
*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
*
* based on max11801_ts.c
*
* which can only report one point at a given time.
* This driver will ignore events in this mode.
*/
-#define REPORT_MODE_SINGLE 0x1
+#define REPORT_MODE_MOUSE 0x1
/*
* Vendor Mode: this mode is used to transfer some vendor specific
* messages.
#define MAX_SUPPORT_POINTS 5
-#define EVENT_MODE 0
-#define EVENT_STATUS 1
#define EVENT_VALID_OFFSET 7
#define EVENT_VALID_MASK (0x1 << EVENT_VALID_OFFSET)
#define EVENT_ID_OFFSET 2
#define MAX_I2C_DATA_LEN 10
-#define EGALAX_MAX_X 32767
-#define EGALAX_MAX_Y 32767
+#define EGALAX_MAX_X 32760
+#define EGALAX_MAX_Y 32760
#define EGALAX_MAX_TRIES 100
-struct egalax_pointer {
- bool valid;
- bool status;
- u16 x;
- u16 y;
-};
-
struct egalax_ts {
struct i2c_client *client;
struct input_dev *input_dev;
- struct egalax_pointer events[MAX_SUPPORT_POINTS];
};
static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
struct egalax_ts *ts = dev_id;
struct input_dev *input_dev = ts->input_dev;
struct i2c_client *client = ts->client;
- struct egalax_pointer *events = ts->events;
u8 buf[MAX_I2C_DATA_LEN];
- int i, id, ret, x, y;
+ int id, ret, x, y, z;
int tries = 0;
bool down, valid;
u8 state;
if (ret < 0)
return IRQ_HANDLED;
- dev_dbg(&client->dev, "recv ret:%d", ret);
- for (i = 0; i < MAX_I2C_DATA_LEN; i++)
- dev_dbg(&client->dev, " %x ", buf[i]);
-
- if (buf[0] != REPORT_MODE_VENDOR
- && buf[0] != REPORT_MODE_SINGLE
- && buf[0] != REPORT_MODE_MTTOUCH) {
- /* invalid point */
- return IRQ_HANDLED;
- }
-
- if (buf[0] == REPORT_MODE_VENDOR) {
- dev_dbg(&client->dev, "vendor message, ignored\n");
+ if (buf[0] != REPORT_MODE_MTTOUCH) {
+ /* ignore mouse events and vendor events */
return IRQ_HANDLED;
}
state = buf[1];
x = (buf[3] << 8) | buf[2];
y = (buf[5] << 8) | buf[4];
-
- /* Currently, the panel Freescale using on SMD board _NOT_
- * support single pointer mode. All event are going to
- * multiple pointer mode. Add single pointer mode according
- * to EETI eGalax I2C programming manual.
- */
- if (buf[0] == REPORT_MODE_SINGLE) {
- input_report_abs(input_dev, ABS_X, x);
- input_report_abs(input_dev, ABS_Y, y);
- input_report_key(input_dev, BTN_TOUCH, !!state);
- input_sync(input_dev);
- return IRQ_HANDLED;
- }
+ z = (buf[7] << 8) | buf[6];
valid = state & EVENT_VALID_MASK;
id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET;
return IRQ_HANDLED;
}
+ input_mt_slot(input_dev, id);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
+
+ dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
+ down ? "down" : "up", id, x, y, z);
+
if (down) {
- events[id].valid = valid;
- events[id].status = down;
- events[id].x = x;
- events[id].y = y;
-
-#ifdef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH
- input_report_abs(input_dev, ABS_X, x);
- input_report_abs(input_dev, ABS_Y, y);
- input_event(ts->input_dev, EV_KEY, BTN_TOUCH, 1);
- input_report_abs(input_dev, ABS_PRESSURE, 1);
-#endif
- } else {
- dev_dbg(&client->dev, "release id:%d\n", id);
- events[id].valid = 0;
- events[id].status = 0;
-#ifdef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH
- input_report_key(input_dev, BTN_TOUCH, 0);
- input_report_abs(input_dev, ABS_PRESSURE, 0);
-#else
- input_report_abs(input_dev, ABS_MT_TRACKING_ID, id);
- input_event(input_dev, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
- input_mt_sync(input_dev);
-#endif
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE, z);
}
-#ifndef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH
- /* report all pointers */
- for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
- if (!events[i].valid)
- continue;
- dev_dbg(&client->dev, "report id:%d valid:%d x:%d y:%d",
- i, valid, x, y);
- input_report_abs(input_dev,
- ABS_MT_TRACKING_ID, i);
- input_report_abs(input_dev,
- ABS_MT_TOUCH_MAJOR, 1);
- input_report_abs(input_dev,
- ABS_MT_POSITION_X, events[i].x);
- input_report_abs(input_dev,
- ABS_MT_POSITION_Y, events[i].y);
- input_mt_sync(input_dev);
- }
-#endif
+ input_mt_report_pointer_emulation(input_dev, true);
input_sync(input_dev);
return IRQ_HANDLED;
return error;
}
- input_dev->name = "eGalax Touch Screen";
- input_dev->phys = "I2C",
+ input_dev->name = "EETI eGalax Touch Screen";
input_dev->id.bustype = BUS_I2C;
- input_dev->id.vendor = 0x0EEF;
- input_dev->id.product = 0x0020;
- input_dev->id.version = 0x0001;
- input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
- __set_bit(ABS_X, input_dev->absbit);
- __set_bit(ABS_Y, input_dev->absbit);
- __set_bit(ABS_PRESSURE, input_dev->absbit);
+
input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0);
-
-#ifndef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH
- input_set_abs_params(input_dev, ABS_MT_POSITION_X,
- 0, EGALAX_MAX_X, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
- 0, EGALAX_MAX_Y, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
- MAX_SUPPORT_POINTS, 0, 0);
-#endif
+ input_set_abs_params(input_dev,
+ ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0);
+ input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0);
+
input_set_drvdata(input_dev, ts);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+++ /dev/null
-/*
- * Copyright (C) 2007-2008 HTC Corporation.
- *
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
- *
- * This driver is adapted from elan8232_i2c.c written by Shan-Fu Chiou
- * <sfchiou@gmail.com> and Jay Tu <jay_tu@htc.com>.
- * This driver is also adapted from the ELAN Touch Screen driver
- * written by Stanley Zeng <stanley.zeng@emc.com.tw>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/input.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/hrtimer.h>
-#include <linux/of_gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/gpio.h>
-
-static const char ELAN_TS_NAME[] = "elan-touch";
-
-#define ELAN_TS_X_MAX 1088
-#define ELAN_TS_Y_MAX 768
-#define ELAN_USER_X_MAX 800
-#define ELAN_USER_Y_MAX 600
-#define IDX_PACKET_SIZE 8
-
-enum {
- hello_packet = 0x55,
- idx_coordinate_packet = 0x5a,
-};
-
-enum {
- idx_finger_state = 7,
-};
-
-static struct workqueue_struct *elan_wq;
-
-static struct elan_data {
- int intr_gpio;
- int use_irq;
- struct hrtimer timer;
- struct work_struct work;
- struct i2c_client *client;
- struct input_dev *input;
- wait_queue_head_t wait;
-} elan_touch_data;
-
-/*--------------------------------------------------------------*/
-static int elan_touch_detect_int_level(void)
-{
- int v;
- v = gpio_get_value(elan_touch_data.intr_gpio);
-
- return v;
-}
-
-static int __elan_touch_poll(struct i2c_client *client)
-{
- int status = 0, retry = 20;
-
- do {
- status = elan_touch_detect_int_level();
- retry--;
- mdelay(20);
- } while (status == 1 && retry > 0);
-
- return (status == 0 ? 0 : -ETIMEDOUT);
-}
-
-static int elan_touch_poll(struct i2c_client *client)
-{
- return __elan_touch_poll(client);
-}
-
-static int __hello_packet_handler(struct i2c_client *client)
-{
- int rc;
- uint8_t buf_recv[4] = { 0 };
-
- rc = elan_touch_poll(client);
-
- if (rc < 0)
- return -EINVAL;
-
- rc = i2c_master_recv(client, buf_recv, 4);
-
- if (rc != 4) {
- return rc;
- } else {
- int i;
- pr_info("hello packet: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
- buf_recv[0], buf_recv[1], buf_recv[2], buf_recv[3]);
-
- for (i = 0; i < 4; i++)
- if (buf_recv[i] != hello_packet)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static inline int elan_touch_parse_xy(uint8_t *data, uint16_t *x,
- uint16_t *y)
-{
- *x = (data[0] & 0xf0);
- *x <<= 4;
- *x |= data[1];
- if (*x >= ELAN_TS_X_MAX)
- *x = ELAN_TS_X_MAX;
- *x = ((((ELAN_TS_X_MAX -
- *x) * 1000) / ELAN_TS_X_MAX) * ELAN_USER_X_MAX) / 1000;
-
- *y = (data[0] & 0x0f);
- *y <<= 8;
- *y |= data[2];
- if (*y >= ELAN_TS_Y_MAX)
- *y = ELAN_TS_Y_MAX;
- *y = ((((ELAN_TS_Y_MAX -
- *y) * 1000) / ELAN_TS_Y_MAX) * ELAN_USER_Y_MAX) / 1000;
-
- return 0;
-}
-
-/* __elan_touch_init -- hand shaking with touch panel
- *
- * 1.recv hello packet
- */
-static int __elan_touch_init(struct i2c_client *client)
-{
- int rc;
- rc = __hello_packet_handler(client);
- if (rc < 0)
- goto hand_shake_failed;
-
-hand_shake_failed:
- return rc;
-}
-
-static int elan_touch_recv_data(struct i2c_client *client, uint8_t * buf)
-{
- int rc, bytes_to_recv = IDX_PACKET_SIZE;
-
- if (buf == NULL)
- return -EINVAL;
-
- memset(buf, 0, bytes_to_recv);
- rc = i2c_master_recv(client, buf, bytes_to_recv);
- if (rc != bytes_to_recv)
- return -EINVAL;
-
- return rc;
-}
-
-static void elan_touch_report_data(struct i2c_client *client, uint8_t * buf)
-{
- switch (buf[0]) {
- case idx_coordinate_packet:
- {
- uint16_t x1, x2, y1, y2;
- uint8_t finger_stat;
-
- finger_stat = (buf[idx_finger_state] & 0x06) >> 1;
-
- if (finger_stat == 0) {
- input_report_key(elan_touch_data.input, BTN_TOUCH, 0);
- input_report_key(elan_touch_data.input, BTN_2, 0);
- } else if (finger_stat == 1) {
- elan_touch_parse_xy(&buf[1], &x1, &y1);
- input_report_abs(elan_touch_data.input, ABS_X, x1);
- input_report_abs(elan_touch_data.input, ABS_Y, y1);
- input_report_key(elan_touch_data.input, BTN_TOUCH, 1);
- input_report_key(elan_touch_data.input, BTN_2, 0);
- } else if (finger_stat == 2) {
- elan_touch_parse_xy(&buf[1], &x1, &y1);
- input_report_abs(elan_touch_data.input, ABS_X, x1);
- input_report_abs(elan_touch_data.input, ABS_Y, y1);
- input_report_key(elan_touch_data.input, BTN_TOUCH, 1);
- elan_touch_parse_xy(&buf[4], &x2, &y2);
- input_report_abs(elan_touch_data.input, ABS_HAT0X, x2);
- input_report_abs(elan_touch_data.input, ABS_HAT0Y, y2);
- input_report_key(elan_touch_data.input, BTN_2, 1);
- }
- input_sync(elan_touch_data.input);
- break;
- }
-
- default:
- break;
- }
-}
-
-static void elan_touch_work_func(struct work_struct *work)
-{
- int rc;
- uint8_t buf[IDX_PACKET_SIZE] = { 0 };
- struct i2c_client *client = elan_touch_data.client;
-
- if (elan_touch_detect_int_level())
- return;
-
- rc = elan_touch_recv_data(client, buf);
- if (rc < 0)
- return;
-
- elan_touch_report_data(client, buf);
-}
-
-static irqreturn_t elan_touch_ts_interrupt(int irq, void *dev_id)
-{
- queue_work(elan_wq, &elan_touch_data.work);
-
- return IRQ_HANDLED;
-}
-
-static enum hrtimer_restart elan_touch_timer_func(struct hrtimer *timer)
-{
- queue_work(elan_wq, &elan_touch_data.work);
- hrtimer_start(&elan_touch_data.timer, ktime_set(0, 12500000),
- HRTIMER_MODE_REL);
-
- return HRTIMER_NORESTART;
-}
-
-static int elan_touch_register_interrupt(struct i2c_client *client)
-{
- int err = 0;
-
- if (client->irq) {
- elan_touch_data.use_irq = 1;
- err =
- request_irq(client->irq, elan_touch_ts_interrupt,
- IRQF_TRIGGER_FALLING, ELAN_TS_NAME,
- &elan_touch_data);
-
- if (err < 0) {
- pr_info("%s(%s): Can't allocate irq %d\n", __FILE__,
- __func__, client->irq);
- elan_touch_data.use_irq = 0;
- }
- }
-
- if (!elan_touch_data.use_irq) {
- hrtimer_init(&elan_touch_data.timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- elan_touch_data.timer.function = elan_touch_timer_func;
- hrtimer_start(&elan_touch_data.timer, ktime_set(1, 0),
- HRTIMER_MODE_REL);
- }
-
- pr_info("elan ts starts in %s mode.\n",
- elan_touch_data.use_irq == 1 ? "interrupt" : "polling");
-
- return 0;
-}
-
-static int elan_touch_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct device_node *np = client->dev.of_node;
- int gpio_elan_cs, gpio_elan_rst, err = 0;
-
- if (!np)
- return -ENODEV;
-
- elan_touch_data.intr_gpio = of_get_named_gpio(np, "gpio_intr", 0);
- if (!gpio_is_valid(elan_touch_data.intr_gpio))
- return -ENODEV;
-
- err = devm_gpio_request_one(&client->dev, elan_touch_data.intr_gpio,
- GPIOF_IN, "gpio_elan_intr");
- if (err < 0) {
- dev_err(&client->dev,
- "request gpio failed: %d\n", err);
- return err;
- }
-
- /* elan touch init */
- gpio_elan_cs = of_get_named_gpio(np, "gpio_elan_cs", 0);
- if (!gpio_is_valid(gpio_elan_cs))
- return -ENODEV;
-
- err = devm_gpio_request_one(&client->dev, gpio_elan_cs,
- GPIOF_OUT_INIT_HIGH, "gpio_elan_cs");
- if (err < 0) {
- dev_err(&client->dev,
- "request gpio failed: %d\n", err);
- return err;
- }
- gpio_set_value(gpio_elan_cs, 0);
-
- gpio_elan_rst = of_get_named_gpio(np, "gpio_elan_rst", 0);
- if (!gpio_is_valid(gpio_elan_rst))
- return -ENODEV;
-
- err = devm_gpio_request_one(&client->dev, gpio_elan_rst,
- GPIOF_OUT_INIT_HIGH, "gpio_elan_rst");
- if (err < 0) {
- dev_err(&client->dev,
- "request gpio failed: %d\n", err);
- return err;
- }
- gpio_set_value(gpio_elan_rst, 0);
- msleep(10);
- gpio_set_value(gpio_elan_rst, 1);
-
- gpio_set_value(gpio_elan_cs, 1);
- msleep(100);
-
- elan_wq = create_singlethread_workqueue("elan_wq");
- if (!elan_wq) {
- err = -ENOMEM;
- goto fail;
- }
-
- elan_touch_data.client = client;
- strlcpy(client->name, ELAN_TS_NAME, I2C_NAME_SIZE);
-
- INIT_WORK(&elan_touch_data.work, elan_touch_work_func);
-
- elan_touch_data.input = input_allocate_device();
- if (elan_touch_data.input == NULL) {
- err = -ENOMEM;
- goto fail;
- }
-
- err = __elan_touch_init(client);
- if (err < 0) {
- dev_err(&client->dev, "elan - Read Hello Packet Failed\n");
- goto fail;
- }
-
- elan_touch_data.input->name = ELAN_TS_NAME;
- elan_touch_data.input->id.bustype = BUS_I2C;
-
- set_bit(EV_SYN, elan_touch_data.input->evbit);
-
- set_bit(EV_KEY, elan_touch_data.input->evbit);
- set_bit(BTN_TOUCH, elan_touch_data.input->keybit);
- set_bit(BTN_2, elan_touch_data.input->keybit);
-
- set_bit(EV_ABS, elan_touch_data.input->evbit);
- set_bit(ABS_X, elan_touch_data.input->absbit);
- set_bit(ABS_Y, elan_touch_data.input->absbit);
- set_bit(ABS_HAT0X, elan_touch_data.input->absbit);
- set_bit(ABS_HAT0Y, elan_touch_data.input->absbit);
-
- input_set_abs_params(elan_touch_data.input, ABS_X, 0, ELAN_USER_X_MAX,
- 0, 0);
- input_set_abs_params(elan_touch_data.input, ABS_Y, 0, ELAN_USER_Y_MAX,
- 0, 0);
- input_set_abs_params(elan_touch_data.input, ABS_HAT0X, 0,
- ELAN_USER_X_MAX, 0, 0);
- input_set_abs_params(elan_touch_data.input, ABS_HAT0Y, 0,
- ELAN_USER_Y_MAX, 0, 0);
-
- err = input_register_device(elan_touch_data.input);
- if (err < 0)
- goto fail;
-
- elan_touch_register_interrupt(elan_touch_data.client);
-
- return 0;
-
-fail:
- input_free_device(elan_touch_data.input);
- if (elan_wq)
- destroy_workqueue(elan_wq);
- return err;
-}
-
-static int elan_touch_remove(struct i2c_client *client)
-{
- if (elan_wq)
- destroy_workqueue(elan_wq);
-
- input_unregister_device(elan_touch_data.input);
-
- if (elan_touch_data.use_irq)
- free_irq(client->irq, client);
- else
- hrtimer_cancel(&elan_touch_data.timer);
- return 0;
-}
-
-/* -------------------------------------------------------------------- */
-static const struct i2c_device_id elan_touch_id[] = {
- {"elan-touch", 0},
- {}
-};
-
-static const struct of_device_id elan_dt_ids[] = {
- {
- .compatible = "elan,elan-touch",
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(of, elan_dt_ids);
-
-static int elan_suspend(struct device *dev)
-{
- return 0;
-}
-
-static int elan_resume(struct device *dev)
-{
- uint8_t buf[IDX_PACKET_SIZE] = { 0 };
-
- if (0 == elan_touch_detect_int_level()) {
- dev_dbg(dev, "Got touch during suspend period.\n");
- /*
- * if touch screen during suspend, recv and drop the
- * data, then touch interrupt pin will return high after
- * receving data.
- */
- elan_touch_recv_data(elan_touch_data.client, buf);
- }
-
- return 0;
-}
-
-static const struct dev_pm_ops elan_dev_pm_ops = {
- .suspend = elan_suspend,
- .resume = elan_resume,
-};
-
-static struct i2c_driver elan_touch_driver = {
- .probe = elan_touch_probe,
- .remove = elan_touch_remove,
- .id_table = elan_touch_id,
- .driver = {
- .name = "elan-touch",
- .owner = THIS_MODULE,
- .of_match_table = elan_dt_ids,
-#ifdef CONFIG_PM
- .pm = &elan_dev_pm_ops,
-#endif
- },
-};
-
-static int __init elan_touch_init(void)
-{
- return i2c_add_driver(&elan_touch_driver);
-}
-
-static void __exit elan_touch_exit(void)
-{
- i2c_del_driver(&elan_touch_driver);
-}
-
-module_init(elan_touch_init);
-module_exit(elan_touch_exit);
-
-MODULE_AUTHOR("Stanley Zeng <stanley.zeng@emc.com.tw>");
-MODULE_DESCRIPTION("ELAN Touch Screen driver");
-MODULE_LICENSE("GPL");
*
* Copyright (C) 2007 8D Technologies inc.
* Raphael Assenat <raph@8d.com>
- * Copyright (C) 2008, 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 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
else
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
- if (of_get_property(child, "retain-state-suspended", NULL))
- led.retain_state_suspended = 1;
if (of_get_property(child, "retain-state-suspended", NULL))
led.retain_state_suspended = 1;
wf->w.left = srect.left;
wf->w.top = srect.top;
wf->w.width = min(srect.width,
- ((__s32)pxp->pxp_conf.s0_param.width - wf->w.left));
+ ((__u32)pxp->pxp_conf.s0_param.width - wf->w.left));
wf->w.height = min(srect.height,
- ((__s32)pxp->pxp_conf.s0_param.height - wf->w.top));
+ ((__u32)pxp->pxp_conf.s0_param.height - wf->w.top));
return 0;
}
* possible racing conditions when working in polling mode */
atomic_set(&core->cts, 0);
- if (!(command == CMD_POWER_DOWN))
- if (!wait_event_timeout(core->command,
- atomic_read(&core->cts),
- usecs_to_jiffies(usecs) + 1))
- dev_warn(&core->client->dev,
- "(%s) [CMD 0x%02x] Answer timeout.\n",
- __func__, command);
+ /* if (unlikely(command == CMD_POWER_DOWN) */
+ if (!wait_event_timeout(core->command,
+ atomic_read(&core->cts),
+ usecs_to_jiffies(usecs) + 1))
+ dev_warn(&core->client->dev,
+ "(%s) [CMD 0x%02x] Answer timeout.\n",
+ __func__, command);
/*
When working in polling mode, for some reason the tuner will
*/
udelay(100);
- err = si476x_core_start(core, true);
+ err = si476x_core_start(core, false);
if (err < 0)
goto disable_regulators;
case SI476X_POWER_DOWN:
core->power_state = next_state;
- err = si476x_core_stop(core, true);
+ err = si476x_core_stop(core, false);
if (err < 0)
core->power_state = SI476X_POWER_INCONSISTENT;
disable_regulators:
memcpy(&core->pinmux, &pdata->pinmux,
sizeof(struct si476x_pinmux));
} else {
- dev_warn(&client->dev, "Using default platform data.\n");
- core->power_up_parameters.xcload = 0x28;
- core->power_up_parameters.func = SI476X_FUNC_FM_RECEIVER;
- core->power_up_parameters.freq = SI476X_FREQ_37P209375_MHZ;
- core->diversity_mode = SI476X_PHDIV_DISABLED;
- core->pinmux.dclk = SI476X_DCLK_DAUDIO;
- core->pinmux.dfs = SI476X_DFS_DAUDIO;
- core->pinmux.dout = SI476X_DOUT_I2S_OUTPUT;
- core->pinmux.xout = SI476X_XOUT_TRISTATE;
+ dev_err(&client->dev, "No platform data provided\n");
+ return -EINVAL;
}
core->supplies[0].supply = "vd";
core->chip_id = id->driver_data;
- /* Power down si476x first */
- core->power_state = SI476X_POWER_UP_FULL;
- si476x_core_set_power_state(core, SI476X_POWER_DOWN);
-
rval = si476x_core_get_revision_info(core);
if (rval < 0) {
rval = -ENODEV;
return 0;
}
-static bool si476x_core_regmap_volatile_register(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE:
- case SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT:
- return false;
- default:
- return true;
- }
-
- return true;
-}
-
-/* These two register is used by the codec, so add reg_default here */
-static struct reg_default si476x_core_reg[] = {
- { 0x202, 0xBB80 },
- { 0x203, 0x1700 },
-};
static const struct regmap_config si476x_regmap_config = {
.reg_bits = 16,
.val_bits = 16,
.max_register = 0x4003,
- .reg_defaults = si476x_core_reg,
- .num_reg_defaults = ARRAY_SIZE(si476x_core_reg),
.writeable_reg = si476x_core_regmap_writable_register,
.readable_reg = si476x_core_regmap_readable_register,
- .volatile_reg = si476x_core_regmap_volatile_register,
.reg_read = si476x_core_regmap_read,
.reg_write = si476x_core_regmap_write,
#include <linux/spinlock.h>
#include <linux/genalloc.h>
-#define SRAM_GRANULARITY 4096
+#define SRAM_GRANULARITY 32
struct sram_dev {
struct gen_pool *pool;
mmc_card_set_blockaddr(card);
}
- card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO];
- card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG];
- card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT];
- card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
-
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
mmc_select_card_type(card);
return err;
}
-static ssize_t mmc_boot_info_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- char *boot_partition[8] = {
- "Device not boot enabled",
- "Boot partition 1 enabled",
- "Boot partition 2 enabled",
- "Reserved",
- "Reserved",
- "Reserved",
- "Reserved",
- "User area enabled for boot"};
-
- char *bus_width[4] = {
- "x1 (sdr) or x4 (ddr) bus width in boot operation mode",
- "x4 (sdr/ddr) bus width in boot operation mode",
- "x8 (sdr/ddr) bus width in boot operation mode",
- "Reserved"};
-
- char *boot_mode[4] = {
- "Use single data rate + backward compatible timings in boot operation",
- "Use single data rate + high speed timings in boot operation mode",
- "Use dual data rate in boot operation",
- "Reserved"};
-
- int partition;
- int width;
- int mode;
- int err;
- u8 *ext_csd = NULL;
- struct mmc_card *card = container_of(dev, struct mmc_card, dev);
-
- /* read it again because user may change it */
- mmc_claim_host(card->host);
- err = mmc_get_ext_csd(card, &ext_csd);
- mmc_release_host(card->host);
- if (err || !ext_csd) {
- pr_err("%s: failed to get ext_csd, err=%d\n",
- mmc_hostname(card->host),
- err);
- return err;
- }
-
- mmc_read_ext_csd(card, ext_csd);
- mmc_free_ext_csd(ext_csd);
-
- partition = (card->ext_csd.boot_config >> 3) & 0x7;
- width = card->ext_csd.boot_bus_width & 0x3;
- mode = (card->ext_csd.boot_bus_width >> 3) & 0x3;
-
- return sprintf(buf,
- "boot_info:0x%02x;\n"
- " ALT_BOOT_MODE:%x - %s\n"
- " DDR_BOOT_MODE:%x - %s\n"
- " HS_BOOTMODE:%x - %s\n"
- "boot_size:%04dKB\n"
- "boot_partition:0x%02x;\n"
- " BOOT_ACK:%x - %s\n"
- " BOOT_PARTITION-ENABLE: %x - %s\n"
- "boot_bus:0x%02x\n"
- " BOOT_MODE:%x - %s\n"
- " RESET_BOOT_BUS_WIDTH:%x - %s\n"
- " BOOT_BUS_WIDTH:%x - %s\n",
-
- card->ext_csd.boot_info,
- !!(card->ext_csd.boot_info & 0x1),
- (card->ext_csd.boot_info & 0x1) ?
- "Supports alternate boot method" :
- "Does not support alternate boot method",
- !!(card->ext_csd.boot_info & 0x2),
- (card->ext_csd.boot_info & 0x2) ?
- "Supports alternate dual data rate during boot" :
- "Does not support dual data rate during boot",
- !!(card->ext_csd.boot_info & 0x4),
- (card->ext_csd.boot_info & 0x4) ?
- "Supports high speed timing during boot" :
- "Does not support high speed timing during boot",
-
- card->ext_csd.boot_size * 128,
-
- card->ext_csd.boot_config,
- !!(card->ext_csd.boot_config & 0x40),
- (card->ext_csd.boot_config & 0x40) ?
- "Boot acknowledge sent during boot operation" :
- "No boot acknowledge sent",
- partition,
- boot_partition[partition],
-
- card->ext_csd.boot_bus_width,
- mode,
- boot_mode[mode],
- !!(card->ext_csd.boot_bus_width & 0x4),
- (card->ext_csd.boot_bus_width & 0x4) ?
- "Retain boot bus width and boot mode after boot operation" :
- "Reset bus width to x1, single data rate and backward"
- "compatible timings after boot operation",
- width,
- bus_width[width]);
-}
-
-/* set up boot partitions */
-static ssize_t
-setup_boot_partitions(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int err, busy = 0;
- u32 part;
- u8 *ext_csd, boot_config;
- struct mmc_command cmd;
- struct mmc_card *card = container_of(dev, struct mmc_card, dev);
-
- BUG_ON(!card);
-
- sscanf(buf, "%d\n", &part);
-
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
- pr_err("%s: invalid mmc version" \
- " mmc version is below version 4!)\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- /* it's a normal SD/MMC but user request to configure boot partition */
- if (card->ext_csd.boot_size <= 0) {
- pr_err("%s: fail to send SWITCH command to card " \
- "to update boot_config of the EXT_CSD!\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- /*
- * partition must be -
- * 0 - user area
- * 1 - boot partition 1
- * 2 - boot partition 2
- * DO NOT switch the partitions that used to be accessed
- * in OS layer HERE
- */
- if (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) {
- pr_err("%s: DO NOT switch the partitions that used to be\n" \
- " accessed in OS layer HERE. please following the\n" \
- " guidance of Documentation/mmc/mmc-dev-parts.txt.\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: could not allocate a buffer to " \
- "receive the ext_csd.\n", mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- mmc_claim_host(card->host);
- err = mmc_send_ext_csd(card, ext_csd);
- if (err) {
- pr_err("%s: unable to read EXT_CSD.\n",
- mmc_hostname(card->host));
- goto err_rtn;
- }
-
- /* enable the boot partition in boot mode */
- /* boot enable be -
- * 0x00 - disable boot enable.
- * 0x08 - boot partition 1 is enabled for boot.
- * 0x10 - boot partition 2 is enabled for boot.
- * 0x38 - User area is enabled for boot.
- */
- switch (part & EXT_CSD_BOOT_PARTITION_ENABLE_MASK) {
- case 0:
- boot_config = (ext_csd[EXT_CSD_PART_CONFIG]
- & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK
- & ~EXT_CSD_BOOT_ACK_ENABLE);
- break;
- case EXT_CSD_BOOT_PARTITION_PART1:
- boot_config = ((ext_csd[EXT_CSD_PART_CONFIG]
- & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
- | EXT_CSD_BOOT_PARTITION_PART1
- | EXT_CSD_BOOT_ACK_ENABLE);
- break;
- case EXT_CSD_BOOT_PARTITION_PART2:
- boot_config = ((ext_csd[EXT_CSD_PART_CONFIG]
- & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
- | EXT_CSD_BOOT_PARTITION_PART2
- | EXT_CSD_BOOT_ACK_ENABLE);
- break;
- case EXT_CSD_BOOT_PARTITION_ENABLE_MASK:
- boot_config = ((ext_csd[EXT_CSD_PART_CONFIG]
- | EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
- & ~EXT_CSD_BOOT_ACK_ENABLE);
- break;
- default:
- pr_err("%s: wrong boot config parameter" \
- " 00 (disable boot), 08 (enable boot1)," \
- "16 (enable boot2), 56 (User area)\n",
- mmc_hostname(card->host));
- err = -EINVAL;
- goto err_rtn;
- }
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_PART_CONFIG, boot_config, card->ext_csd.part_time);
- if (err) {
- pr_err("%s: fail to send SWITCH command to card " \
- "to update boot_config of the EXT_CSD!\n",
- mmc_hostname(card->host));
- goto err_rtn;
- }
-
- /* waiting for the card to finish the busy state */
- do {
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err || busy > 100) {
- pr_err("%s: failed to wait for" \
- "the busy state to end.\n",
- mmc_hostname(card->host));
- break;
- }
-
- if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
- pr_info("%s: card is in busy state" \
- "pls wait for busy state to end.\n",
- mmc_hostname(card->host));
- }
- busy++;
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
-
- /* Now check whether it works */
- err = mmc_send_ext_csd(card, ext_csd);
- if (err) {
- pr_err("%s: %d unable to re-read EXT_CSD.\n",
- mmc_hostname(card->host), err);
- goto err_rtn;
- }
-
- card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG];
-
-err_rtn:
- mmc_release_host(card->host);
- kfree(ext_csd);
- if (err)
- return err;
- else
- return count;
-}
-
-/* configure the boot bus */
-static ssize_t
-setup_boot_bus(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int err, busy = 0;
- u32 boot_bus, new_bus;
- u8 *ext_csd;
- struct mmc_command cmd;
- struct mmc_card *card = container_of(dev, struct mmc_card, dev);
-
- BUG_ON(!card);
-
- sscanf(buf, "%d\n", &boot_bus);
-
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
- pr_err("%s: invalid mmc version" \
- " mmc version is below version 4!)\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- /* it's a normal SD/MMC but user request to configure boot bus */
- if (card->ext_csd.boot_size <= 0) {
- pr_err("%s: this is a normal SD/MMC card" \
- " but you request to configure boot bus !\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: could not allocate a buffer to " \
- "receive the ext_csd.\n", mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- mmc_claim_host(card->host);
- err = mmc_send_ext_csd(card, ext_csd);
- if (err) {
- pr_err("%s: unable to read EXT_CSD.\n",
- mmc_hostname(card->host));
- goto err_rtn;
- }
-
- /* Configure the boot bus width when boot partition is enabled */
- if (((boot_bus & EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK) >> 3) > 2
- || (boot_bus & EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK) > 2
- || (boot_bus & ~EXT_CSD_BOOT_BUS_WIDTH_MASK) > 0) {
- pr_err("%s: Invalid inputs!\n",
- mmc_hostname(card->host));
- err = -EINVAL;
- goto err_rtn;
- }
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BOOT_BUS_WIDTH, boot_bus, card->ext_csd.part_time);
- if (err) {
- pr_err("%s: fail to send SWITCH command to card " \
- "to update boot_config of the EXT_CSD!\n",
- mmc_hostname(card->host));
- goto err_rtn;
- }
-
- /* waiting for the card to finish the busy state */
- do {
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err || busy > 100) {
- pr_err("%s: failed to wait for" \
- "the busy state to end.\n",
- mmc_hostname(card->host));
- break;
- }
-
- if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
- pr_info("%s: card is in busy state" \
- "pls wait for busy state to end.\n",
- mmc_hostname(card->host));
- }
- busy++;
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
-
- /* Now check whether it works */
- err = mmc_send_ext_csd(card, ext_csd);
- if (err) {
- pr_err("%s: %d unable to re-read EXT_CSD.\n",
- mmc_hostname(card->host), err);
- goto err_rtn;
- }
-
- new_bus = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
- if (boot_bus != new_bus) {
- pr_err("%s: after SWITCH, current boot bus mode %d" \
- " is not same as requested bus mode %d!\n",
- mmc_hostname(card->host), new_bus, boot_bus);
- goto err_rtn;
- }
- card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
-
-err_rtn:
- mmc_release_host(card->host);
- mmc_free_ext_csd(ext_csd);
- if (err)
- return err;
- else
- return count;
-}
-
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
-DEVICE_ATTR(boot_info, S_IRUGO, mmc_boot_info_show, NULL);
-DEVICE_ATTR(boot_config, S_IWUGO, NULL, setup_boot_partitions);
-DEVICE_ATTR(boot_bus_config, S_IWUGO, NULL, setup_boot_bus);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_enhanced_area_size.attr,
&dev_attr_raw_rpmb_size_mult.attr,
&dev_attr_rel_sectors.attr,
- &dev_attr_boot_info.attr,
- &dev_attr_boot_config.attr,
- &dev_attr_boot_bus_config.attr,
NULL,
};
ATTRIBUTE_GROUPS(mmc_std);
#ifdef CONFIG_PM
void sdhci_enable_irq_wakeups(struct sdhci_host *host)
{
- int gpio_cd = mmc_gpio_get_cd(host->mmc);
u8 val;
u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
| SDHCI_WAKE_ON_INT;
val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
val |= mask ;
/* Avoid fake wake up */
- if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION ||
- !IS_ERR_VALUE(gpio_cd))
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE);
sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
}
#define UDELAY(map, chip, adr, usec) \
do { \
+ mutex_unlock(&chip->mutex); \
cfi_udelay(usec); \
+ mutex_lock(&chip->mutex); \
} while (0)
#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
do { \
+ mutex_unlock(&chip->mutex); \
INVALIDATE_CACHED_RANGE(map, adr, len); \
cfi_udelay(usec); \
+ mutex_lock(&chip->mutex); \
} while (0)
#endif
dbg_gen("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));
dbg_gen("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
- if (ubi->mtd->numeraseregions > 1) {
+ if (ubi->mtd->numeraseregions != 0) {
/*
* Some flashes have several erase regions. Different regions
* may have different eraseblock size and other
#include <linux/memblock.h>
#include <linux/memory.h>
#include <linux/version.h>
-#include <asm/page.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
-#include <linux/iram_alloc.h>
-#include <mach/clock.h>
-#include <mach/hardware.h>
-#include <mach/mxc_vpu.h>
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
#include <linux/genalloc.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/clk.h>
#include <linux/mxc_vpu.h>
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-#include <mach/busfreq.h>
-#include <mach/common.h>
-#else
-#include <asm/sizes.h>
-#endif
/* Define one new pgprot which combined uncached and XN(never executable) */
#define pgprot_noncachedxn(prot) \
struct work_struct work;
struct workqueue_struct *workqueue;
struct mutex lock;
+ const struct mxc_vpu_soc_data *soc_data;
+ int clk_enabled;
+ struct list_head users;
+};
+
+struct vpu_user_data {
+ struct vpu_priv *vpu_data;
+ struct list_head list;
+ int clk_enable_cnt;
};
/* To track the allocated memory buffer */
u32 end;
};
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+struct mxc_vpu_soc_data {
+ unsigned vpu_pwr_mgmnt:1,
+ regulator_required:1,
+ quirk_subblk_en:1,
+ is_mx51:1,
+ is_mx53:1,
+ is_mx6dl:1,
+ is_mx6q:1,
+ has_jpu:1;
+};
+
static struct gen_pool *iram_pool;
static u32 iram_base;
-#endif
-static LIST_HEAD(head);
+static LIST_HEAD(mem_list);
static int vpu_major;
-static int vpu_clk_usercount;
static struct class *vpu_class;
static struct vpu_priv vpu_data;
static u8 open_count;
static struct clk *vpu_clk;
-static struct vpu_mem_desc bitwork_mem = { 0 };
-static struct vpu_mem_desc pic_para_mem = { 0 };
-static struct vpu_mem_desc user_data_mem = { 0 };
-static struct vpu_mem_desc share_mem = { 0 };
-static struct vpu_mem_desc vshare_mem = { 0 };
+static struct vpu_mem_desc bitwork_mem;
+static struct vpu_mem_desc pic_para_mem;
+static struct vpu_mem_desc user_data_mem;
+static struct vpu_mem_desc share_mem;
+static struct vpu_mem_desc vshare_mem;
static void __iomem *vpu_base;
static int vpu_ipi_irq;
static u32 phy_vpu_base_addr;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
-static phys_addr_t top_address_DRAM;
-static struct mxc_vpu_platform_data *vpu_plat;
-#endif
static struct device *vpu_dev;
static int codec_done;
static wait_queue_head_t vpu_queue;
-#ifdef CONFIG_SOC_IMX6Q
-#define MXC_VPU_HAS_JPU
-#endif
-
-#ifdef MXC_VPU_HAS_JPU
static int vpu_jpu_irq;
-#endif
#ifdef CONFIG_PM
static unsigned int regBk[64];
static unsigned int pc_before_suspend;
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
static struct regulator *vpu_regulator;
-#endif
-static atomic_t clk_cnt_from_ioc = ATOMIC_INIT(0);
-#define READ_REG(x) readl_relaxed(vpu_base + x)
-#define WRITE_REG(val, x) writel_relaxed(val, vpu_base + x)
+#define READ_REG(x) readl_relaxed(vpu_base + (x))
+#define WRITE_REG(val, x) writel_relaxed(val, vpu_base + (x))
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-/* redirect to static functions */
-static int cpu_is_mx6dl(void)
+static int vpu_clk_enable(struct vpu_priv *vpu_data)
{
- int ret;
- ret = of_machine_is_compatible("fsl,imx6dl");
- return ret;
-}
+ int ret = 0;
-static int cpu_is_mx6q(void)
-{
- int ret;
- ret = of_machine_is_compatible("fsl,imx6q");
- return ret;
-}
-#endif
+ if (vpu_data->clk_enabled++ == 0)
+ ret = clk_prepare_enable(vpu_clk);
-static void vpu_reset(void)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
- device_reset(vpu_dev);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
- imx_src_reset_vpu();
-#else
- if (vpu_plat->reset)
- vpu_plat->reset();
-#endif
-}
+ if (WARN_ON(vpu_data->clk_enabled <= 0))
+ return -EINVAL;
-static long vpu_power_get(bool on)
-{
- long ret = 0;
-
- if (on) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- vpu_regulator = regulator_get(NULL, "cpu_vddvpu");
- ret = IS_ERR(vpu_regulator);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
- vpu_regulator = devm_regulator_get(vpu_dev, "pu");
- ret = IS_ERR(vpu_regulator);
-#endif
- } else {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- if (!IS_ERR(vpu_regulator))
- regulator_put(vpu_regulator);
-#endif
- }
return ret;
}
-static void vpu_power_up(bool on)
+static int vpu_clk_disable(struct vpu_priv *vpu_data)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
- int ret = 0;
+ if (WARN_ON(vpu_data->clk_enabled == 0))
+ return -EINVAL;
- if (on) {
- if (!IS_ERR(vpu_regulator)) {
- ret = regulator_enable(vpu_regulator);
- if (ret)
- dev_err(vpu_dev, "failed to power up vpu\n");
- }
- } else {
- if (!IS_ERR(vpu_regulator)) {
- ret = regulator_disable(vpu_regulator);
- if (ret)
- dev_err(vpu_dev, "failed to power down vpu\n");
- }
- }
-#else
- imx_gpc_power_up_pu(on);
-#endif
+ if (--vpu_data->clk_enabled == 0)
+ clk_disable_unprepare(vpu_clk);
+ return 0;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
-static void request_bus_freq(int freq)
+static inline int vpu_reset(void)
{
+ return device_reset(vpu_dev);
}
-static void release_bus_freq(int freq)
+static void vpu_power_up(void)
{
-}
+ int ret;
-static int cpu_is_mx53(void)
-{
- return 0;
+ if (IS_ERR(vpu_regulator))
+ return;
+
+ ret = regulator_enable(vpu_regulator);
+ if (ret)
+ dev_err(vpu_dev, "failed to power up vpu: %d\n", ret);
}
-static int cpu_is_mx51(void)
+static void vpu_power_down(void)
{
- return 0;
-}
+ int ret;
-#define VM_RESERVED 0
-#define BUS_FREQ_HIGH 0
+ if (IS_ERR(vpu_regulator))
+ return;
-#endif
+ ret = regulator_disable(vpu_regulator);
+ if (ret)
+ dev_err(vpu_dev, "failed to power down vpu: %d\n", ret);
+}
/*!
* Private function to alloc dma buffer
*/
static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem)
{
- mem->cpu_addr = (unsigned long)
- dma_alloc_coherent(NULL, PAGE_ALIGN(mem->size),
- (dma_addr_t *) (&mem->phy_addr),
- GFP_DMA | GFP_KERNEL);
- dev_dbg(vpu_dev, "[ALLOC] mem alloc cpu_addr = 0x%x\n", mem->cpu_addr);
- if ((void *)(mem->cpu_addr) == NULL) {
+ mem->cpu_addr = dma_alloc_coherent(vpu_dev, PAGE_ALIGN(mem->size),
+ &mem->phy_addr,
+ GFP_DMA | GFP_KERNEL);
+ dev_dbg(vpu_dev, "[ALLOC] mem alloc cpu_addr = %p\n", mem->cpu_addr);
+ if (mem->cpu_addr == NULL) {
dev_err(vpu_dev, "Physical memory allocation error!\n");
- return -1;
+ return -ENOMEM;
}
return 0;
}
*/
static void vpu_free_dma_buffer(struct vpu_mem_desc *mem)
{
- if (mem->cpu_addr != 0) {
- dma_free_coherent(0, PAGE_ALIGN(mem->size),
- (void *)mem->cpu_addr, mem->phy_addr);
- }
+ if (mem->cpu_addr != NULL)
+ dma_free_coherent(vpu_dev, PAGE_ALIGN(mem->size),
+ mem->cpu_addr, mem->phy_addr);
}
/*!
struct memalloc_record *rec, *n;
struct vpu_mem_desc mem;
- list_for_each_entry_safe(rec, n, &head, list) {
+ list_for_each_entry_safe(rec, n, &mem_list, list) {
mem = rec->mem;
if (mem.cpu_addr != 0) {
vpu_free_dma_buffer(&mem);
static inline void vpu_worker_callback(struct work_struct *w)
{
- struct vpu_priv *dev = container_of(w, struct vpu_priv,
- work);
+ struct vpu_priv *dev = container_of(w, struct vpu_priv, work);
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
/*!
* @brief vpu jpu interrupt handler
*/
-#ifdef MXC_VPU_HAS_JPU
static irqreturn_t vpu_jpu_irq_handler(int irq, void *dev_id)
{
struct vpu_priv *dev = dev_id;
return IRQ_HANDLED;
}
-#endif
-
-/*!
- * @brief check phy memory prepare to pass to vpu is valid or not, we
- * already address some issue that if pass a wrong address to vpu
- * (like virtual address), system will hang.
- *
- * @return true return is a valid phy memory address, false return not.
- */
-bool vpu_is_valid_phy_memory(u32 paddr)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- if (paddr > top_address_DRAM)
- return false;
-#endif
-
- return true;
-}
/*!
* @brief open function for vpu file operation
*/
static int vpu_open(struct inode *inode, struct file *filp)
{
+ struct vpu_user_data *user_data = devm_kzalloc(vpu_dev,
+ sizeof(*user_data),
+ GFP_KERNEL);
+ if (user_data == NULL)
+ return -ENOMEM;
+
+ user_data->vpu_data = &vpu_data;
+
+ INIT_LIST_HEAD(&user_data->list);
+ list_add(&user_data->list, &vpu_data.users);
mutex_lock(&vpu_data.lock);
if (open_count++ == 0) {
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
pm_runtime_get_sync(vpu_dev);
-#endif
- vpu_power_up(true);
-
-#ifdef CONFIG_SOC_IMX6Q
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
- if (READ_REG(BIT_CUR_PC))
- dev_dbg(vpu_dev, "Not power off before vpu open!\n");
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
-#endif
+ vpu_power_up();
}
- filp->private_data = (void *)(&vpu_data);
+ filp->private_data = user_data;
mutex_unlock(&vpu_data.lock);
return 0;
}
static long vpu_ioctl(struct file *filp, u_int cmd,
u_long arg)
{
- int ret = 0;
+ int ret = -EINVAL;
+ struct vpu_user_data *user_data = filp->private_data;
+ struct vpu_priv *vpu_data = user_data->vpu_data;
switch (cmd) {
case VPU_IOC_PHYMEM_ALLOC:
- {
- struct memalloc_record *rec;
+ {
+ struct memalloc_record *rec;
- rec = kzalloc(sizeof(*rec), GFP_KERNEL);
- if (!rec)
- return -ENOMEM;
+ rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+ if (!rec)
+ return -ENOMEM;
- ret = copy_from_user(&(rec->mem),
- (struct vpu_mem_desc *)arg,
- sizeof(struct vpu_mem_desc));
- if (ret) {
- kfree(rec);
- return -EFAULT;
- }
+ if (copy_from_user(&rec->mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc))) {
+ kfree(rec);
+ return -EFAULT;
+ }
- dev_dbg(vpu_dev, "[ALLOC] mem alloc size = 0x%x\n",
- rec->mem.size);
+ dev_dbg(vpu_dev, "[ALLOC] mem alloc size = 0x%x\n",
+ rec->mem.size);
- ret = vpu_alloc_dma_buffer(&(rec->mem));
- if (ret == -1) {
- kfree(rec);
- dev_err(vpu_dev,
- "Physical memory allocation error!\n");
- break;
- }
- ret = copy_to_user((void __user *)arg, &(rec->mem),
- sizeof(struct vpu_mem_desc));
- if (ret) {
- kfree(rec);
- ret = -EFAULT;
- break;
- }
+ ret = vpu_alloc_dma_buffer(&rec->mem);
+ if (ret) {
+ kfree(rec);
+ return ret;
+ }
+ if (copy_to_user((void __user *)arg, &rec->mem,
+ sizeof(struct vpu_mem_desc))) {
+ kfree(rec);
+ return -EFAULT;
+ }
- mutex_lock(&vpu_data.lock);
- list_add(&rec->list, &head);
- mutex_unlock(&vpu_data.lock);
+ mutex_lock(&vpu_data->lock);
+ list_add(&rec->list, &mem_list);
+ mutex_unlock(&vpu_data->lock);
- break;
- }
+ break;
+ }
case VPU_IOC_PHYMEM_FREE:
- {
- struct memalloc_record *rec, *n;
- struct vpu_mem_desc vpu_mem;
-
- ret = copy_from_user(&vpu_mem,
- (struct vpu_mem_desc *)arg,
- sizeof(struct vpu_mem_desc));
- if (ret)
- return -EACCES;
-
- dev_dbg(vpu_dev, "[FREE] mem freed cpu_addr = 0x%x\n",
- vpu_mem.cpu_addr);
- if ((void *)vpu_mem.cpu_addr != NULL)
- vpu_free_dma_buffer(&vpu_mem);
-
- mutex_lock(&vpu_data.lock);
- list_for_each_entry_safe(rec, n, &head, list) {
- if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
- /* delete from list */
- list_del(&rec->list);
- kfree(rec);
- break;
- }
+ {
+ struct memalloc_record *rec, *n;
+ struct vpu_mem_desc vpu_mem;
+
+ if (copy_from_user(&vpu_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc)))
+ return -EFAULT;
+
+ dev_dbg(vpu_dev, "[FREE] mem freed cpu_addr = %p\n",
+ vpu_mem.cpu_addr);
+ if (vpu_mem.cpu_addr != NULL)
+ vpu_free_dma_buffer(&vpu_mem);
+
+ mutex_lock(&vpu_data->lock);
+ list_for_each_entry_safe(rec, n, &mem_list, list) {
+ if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
+ list_del(&rec->list);
+ break;
}
- mutex_unlock(&vpu_data.lock);
-
- break;
}
+ kfree(rec);
+ mutex_unlock(&vpu_data->lock);
+
+ break;
+ }
case VPU_IOC_WAIT4INT:
- {
- u_long timeout = (u_long) arg;
- if (!wait_event_interruptible_timeout
- (vpu_queue, irq_status != 0,
- msecs_to_jiffies(timeout))) {
- dev_warn(vpu_dev, "VPU blocking: timeout.\n");
- ret = -ETIME;
- } else if (signal_pending(current)) {
- dev_warn(vpu_dev, "VPU interrupt received.\n");
- ret = -ERESTARTSYS;
- } else
- irq_status = 0;
- break;
+ {
+ u_long timeout = arg;
+
+ ret = wait_event_interruptible_timeout(vpu_queue,
+ irq_status != 0,
+ msecs_to_jiffies(timeout));
+ if (ret == 0) {
+ dev_warn(vpu_dev, "VPU blocking: timeout.\n");
+ ret = -ETIMEDOUT;
+ } else if (signal_pending(current)) {
+ dev_warn(vpu_dev, "VPU interrupt received.\n");
+ ret = -ERESTARTSYS;
+ } else {
+ irq_status = 0;
}
+ break;
+ }
case VPU_IOC_IRAM_SETTING:
- {
- ret = copy_to_user((void __user *)arg, &iram,
- sizeof(struct iram_setting));
- if (ret)
- ret = -EFAULT;
+ ret = copy_to_user((void __user *)arg, &iram,
+ sizeof(struct iram_setting));
+ if (ret)
+ ret = -EFAULT;
- break;
- }
+ break;
case VPU_IOC_CLKGATE_SETTING:
- {
- u32 clkgate_en;
+ {
+ u32 clkgate_en;
- if (get_user(clkgate_en, (u32 __user *) arg))
- return -EFAULT;
+ if (get_user(clkgate_en, (u32 __user *)arg))
+ return -EFAULT;
- if (clkgate_en) {
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
- atomic_inc(&clk_cnt_from_ioc);
+ mutex_lock(&vpu_data->lock);
+ if (clkgate_en) {
+ ret = vpu_clk_enable(vpu_data);
+ if (ret == 0)
+ user_data->clk_enable_cnt++;
+ } else {
+ if (user_data->clk_enable_cnt == 0) {
+ ret = -EINVAL;
} else {
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- atomic_dec(&clk_cnt_from_ioc);
+ if (--user_data->clk_enable_cnt == 0)
+ vpu_clk_disable(vpu_data);
+ ret = 0;
}
-
- break;
}
+ mutex_unlock(&vpu_data->lock);
+ break;
+ }
case VPU_IOC_GET_SHARE_MEM:
- {
- mutex_lock(&vpu_data.lock);
- if (share_mem.cpu_addr != 0) {
- ret = copy_to_user((void __user *)arg,
- &share_mem,
- sizeof(struct vpu_mem_desc));
- mutex_unlock(&vpu_data.lock);
- break;
- } else {
- if (copy_from_user(&share_mem,
- (struct vpu_mem_desc *)arg,
- sizeof(struct vpu_mem_desc))) {
- mutex_unlock(&vpu_data.lock);
- return -EFAULT;
- }
- if (vpu_alloc_dma_buffer(&share_mem) == -1)
- ret = -EFAULT;
- else {
- if (copy_to_user((void __user *)arg,
- &share_mem,
- sizeof(struct
- vpu_mem_desc)))
- ret = -EFAULT;
- }
+ mutex_lock(&vpu_data->lock);
+ if (share_mem.cpu_addr == NULL) {
+ if (copy_from_user(&share_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc))) {
+ mutex_unlock(&vpu_data->lock);
+ return -EFAULT;
+ }
+ ret = vpu_alloc_dma_buffer(&share_mem);
+ if (ret) {
+ mutex_unlock(&vpu_data->lock);
+ return ret;
}
- mutex_unlock(&vpu_data.lock);
- break;
}
+ if (copy_to_user((void __user *)arg,
+ &share_mem,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ mutex_unlock(&vpu_data->lock);
+ break;
case VPU_IOC_REQ_VSHARE_MEM:
- {
- mutex_lock(&vpu_data.lock);
- if (vshare_mem.cpu_addr != 0) {
- ret = copy_to_user((void __user *)arg,
- &vshare_mem,
- sizeof(struct vpu_mem_desc));
- mutex_unlock(&vpu_data.lock);
- break;
- } else {
- if (copy_from_user(&vshare_mem,
- (struct vpu_mem_desc *)arg,
- sizeof(struct
- vpu_mem_desc))) {
- mutex_unlock(&vpu_data.lock);
- return -EFAULT;
- }
- /* vmalloc shared memory if not allocated */
- if (!vshare_mem.cpu_addr)
- vshare_mem.cpu_addr =
- (unsigned long)
- vmalloc_user(vshare_mem.size);
- if (copy_to_user
- ((void __user *)arg, &vshare_mem,
- sizeof(struct vpu_mem_desc)))
- ret = -EFAULT;
+ mutex_lock(&vpu_data->lock);
+ if (vshare_mem.cpu_addr == NULL) {
+ if (copy_from_user(&vshare_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct
+ vpu_mem_desc))) {
+ mutex_unlock(&vpu_data->lock);
+ return -EFAULT;
+ }
+ vshare_mem.cpu_addr = vmalloc_user(vshare_mem.size);
+ if (vshare_mem.cpu_addr == NULL) {
+ mutex_unlock(&vpu_data->lock);
+ return -ENOMEM;
}
- mutex_unlock(&vpu_data.lock);
- break;
}
+ if (copy_to_user((void __user *)arg, &vshare_mem,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ mutex_unlock(&vpu_data->lock);
+ break;
case VPU_IOC_GET_WORK_ADDR:
- {
- if (bitwork_mem.cpu_addr != 0) {
- ret =
- copy_to_user((void __user *)arg,
- &bitwork_mem,
- sizeof(struct vpu_mem_desc));
- break;
- } else {
- if (copy_from_user(&bitwork_mem,
- (struct vpu_mem_desc *)arg,
- sizeof(struct vpu_mem_desc)))
- return -EFAULT;
-
- if (vpu_alloc_dma_buffer(&bitwork_mem) == -1)
- ret = -EFAULT;
- else if (copy_to_user((void __user *)arg,
- &bitwork_mem,
- sizeof(struct
- vpu_mem_desc)))
- ret = -EFAULT;
- }
- break;
+ if (bitwork_mem.cpu_addr == 0) {
+ if (copy_from_user(&bitwork_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc)))
+ return -EFAULT;
+
+ ret = vpu_alloc_dma_buffer(&bitwork_mem);
+ if (ret)
+ return ret;
}
+ if (copy_to_user((void __user *)arg,
+ &bitwork_mem,
+ sizeof(struct
+ vpu_mem_desc)))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ break;
/*
- * The following two ioctl is used when user allocates working buffer
- * and register it to vpu driver.
+ * The following two ioctls are used when user allocates a working buffer
+ * and registers it to vpu driver.
*/
case VPU_IOC_QUERY_BITWORK_MEM:
- {
- if (copy_to_user((void __user *)arg,
- &bitwork_mem,
- sizeof(struct vpu_mem_desc)))
- ret = -EFAULT;
- break;
- }
+ if (copy_to_user((void __user *)arg,
+ &bitwork_mem,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ break;
case VPU_IOC_SET_BITWORK_MEM:
- {
- if (copy_from_user(&bitwork_mem,
- (struct vpu_mem_desc *)arg,
- sizeof(struct vpu_mem_desc)))
- ret = -EFAULT;
- break;
- }
+ if (copy_from_user(&bitwork_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ break;
case VPU_IOC_SYS_SW_RESET:
- {
- vpu_reset();
- break;
- }
- case VPU_IOC_REG_DUMP:
+ ret = vpu_reset();
break;
+ case VPU_IOC_REG_DUMP:
case VPU_IOC_PHYMEM_DUMP:
+ ret = 0;
break;
case VPU_IOC_PHYMEM_CHECK:
{
struct vpu_mem_desc check_memory;
+
ret = copy_from_user(&check_memory,
- (void __user *)arg,
- sizeof(struct vpu_mem_desc));
+ (void __user *)arg,
+ sizeof(struct vpu_mem_desc));
if (ret != 0) {
dev_err(vpu_dev, "copy from user failure:%d\n", ret);
ret = -EFAULT;
break;
}
- ret = vpu_is_valid_phy_memory((u32)check_memory.phy_addr);
-
- dev_dbg(vpu_dev, "vpu: memory phy:0x%x %s phy memory\n",
- check_memory.phy_addr, (ret ? "is" : "isn't"));
- /* borrow .size to pass back the result. */
- check_memory.size = ret;
- ret = copy_to_user((void __user *)arg, &check_memory,
- sizeof(struct vpu_mem_desc));
- if (ret) {
+ check_memory.size = 1;
+ if (copy_to_user((void __user *)arg, &check_memory,
+ sizeof(struct vpu_mem_desc)))
ret = -EFAULT;
- break;
- }
+ else
+ ret = 0;
break;
}
case VPU_IOC_LOCK_DEV:
- {
- u32 lock_en;
-
- if (get_user(lock_en, (u32 __user *) arg))
- return -EFAULT;
+ {
+ u32 lock_en;
- if (lock_en)
- mutex_lock(&vpu_data.lock);
- else
- mutex_unlock(&vpu_data.lock);
+ if (get_user(lock_en, (u32 __user *)arg))
+ return -EFAULT;
- break;
- }
+ if (lock_en)
+ mutex_lock(&vpu_data->lock);
+ else
+ mutex_unlock(&vpu_data->lock);
+ ret = 0;
+ break;
+ }
default:
- {
- dev_err(vpu_dev, "No such IOCTL, cmd is %d\n", cmd);
- ret = -EINVAL;
- break;
- }
+ dev_err(vpu_dev, "No such IOCTL, cmd is %d\n", cmd);
}
return ret;
}
*/
static int vpu_release(struct inode *inode, struct file *filp)
{
- int i;
unsigned long timeout;
+ struct vpu_user_data *user_data = filp->private_data;
+ struct vpu_priv *vpu_data = user_data->vpu_data;
- mutex_lock(&vpu_data.lock);
-
- if (open_count > 0 && !(--open_count)) {
+ mutex_lock(&vpu_data->lock);
+ if (open_count > 0 && !--open_count) {
/* Wait for vpu go to idle state */
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
+ vpu_clk_enable(vpu_data);
if (READ_REG(BIT_CUR_PC)) {
timeout = jiffies + HZ;
break;
}
}
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
/* Clean up interrupt */
- cancel_work_sync(&vpu_data.work);
- flush_workqueue(vpu_data.workqueue);
+ cancel_work_sync(&vpu_data->work);
+ flush_workqueue(vpu_data->workqueue);
irq_status = 0;
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
if (READ_REG(BIT_BUSY_FLAG)) {
-
- if (cpu_is_mx51() || cpu_is_mx53()) {
+ if (vpu_data->soc_data->is_mx51 ||
+ vpu_data->soc_data->is_mx53) {
dev_err(vpu_dev,
"fatal error: can't gate/power off when VPU is busy\n");
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- mutex_unlock(&vpu_data.lock);
- return -EFAULT;
+ vpu_clk_disable(vpu_data);
+ mutex_unlock(&vpu_data->lock);
+ return -EBUSY;
}
-
-#ifdef CONFIG_SOC_IMX6Q
- if (cpu_is_mx6dl() || cpu_is_mx6q()) {
+ if (vpu_data->soc_data->is_mx6dl ||
+ vpu_data->soc_data->is_mx6q) {
WRITE_REG(0x11, 0x10F0);
timeout = jiffies + HZ;
while (READ_REG(0x10F4) != 0x77) {
dev_err(vpu_dev,
"fatal error: can't gate/power off when VPU is busy\n");
WRITE_REG(0x0, 0x10F0);
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- mutex_unlock(&vpu_data.lock);
- return -EFAULT;
- } else
- vpu_reset();
+ vpu_clk_disable(vpu_data);
+ mutex_unlock(&vpu_data->lock);
+ return -EBUSY;
+ }
+ vpu_reset();
}
-#endif
}
}
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
vpu_free_buffers();
/* Free shared memory when vpu device is idle */
vpu_free_dma_buffer(&share_mem);
share_mem.cpu_addr = 0;
- vfree((void *)vshare_mem.cpu_addr);
+ vfree(vshare_mem.cpu_addr);
vshare_mem.cpu_addr = 0;
- vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
- for (i = 0; i < vpu_clk_usercount; i++) {
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- atomic_dec(&clk_cnt_from_ioc);
- }
+ if (user_data->clk_enable_cnt)
+ vpu_clk_disable(vpu_data);
- vpu_power_up(false);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ vpu_clk_disable(vpu_data);
+ vpu_power_down();
pm_runtime_put_sync_suspend(vpu_dev);
-#endif
-
+ devm_kfree(vpu_dev, user_data);
}
- mutex_unlock(&vpu_data.lock);
+ mutex_unlock(&vpu_data->lock);
return 0;
}
*/
static int vpu_fasync(int fd, struct file *filp, int mode)
{
- struct vpu_priv *dev = (struct vpu_priv *)filp->private_data;
- return fasync_helper(fd, filp, mode, &dev->async_queue);
+ struct vpu_user_data *user_data = filp->private_data;
+ struct vpu_priv *vpu_data = user_data->vpu_data;
+ return fasync_helper(fd, filp, mode, &vpu_data->async_queue);
}
/*!
{
unsigned long pfn;
- vm->vm_flags |= VM_IO | VM_RESERVED;
+ vm->vm_flags |= VM_IO;
/*
* Since vpu registers have been mapped with ioremap() at probe
* which L_PTE_XN is 1, and the same physical address must be
*/
vm->vm_page_prot = pgprot_noncachedxn(vm->vm_page_prot);
pfn = phy_vpu_base_addr >> PAGE_SHIFT;
- dev_dbg(vpu_dev, "size=0x%x, page no.=0x%x\n",
- (int)(vm->vm_end - vm->vm_start), (int)pfn);
- return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
- vm->vm_page_prot) ? -EAGAIN : 0;
+ dev_dbg(vpu_dev, "size=0x%lx, page no.=0x%lx\n",
+ vm->vm_end - vm->vm_start, pfn);
+ return remap_pfn_range(vm, vm->vm_start, pfn,
+ vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
}
/*!
*/
static int vpu_map_dma_mem(struct file *fp, struct vm_area_struct *vm)
{
- int request_size;
- request_size = vm->vm_end - vm->vm_start;
+ size_t request_size = vm->vm_end - vm->vm_start;
- dev_dbg(vpu_dev, "start=0x%x, pgoff=0x%x, size=0x%x\n",
- (unsigned int)(vm->vm_start), (unsigned int)(vm->vm_pgoff),
- request_size);
+ dev_dbg(vpu_dev, "start=0x%08lx, pgoff=0x%08lx, size=%zx\n",
+ vm->vm_start, vm->vm_pgoff, request_size);
- vm->vm_flags |= VM_IO | VM_RESERVED;
+ vm->vm_flags |= VM_IO;
vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot);
return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
request_size, vm->vm_page_prot) ? -EAGAIN : 0;
-
}
/* !
*/
static int vpu_map_vshare_mem(struct file *fp, struct vm_area_struct *vm)
{
- int ret = -EINVAL;
+ int ret;
ret = remap_vmalloc_range(vm, (void *)(vm->vm_pgoff << PAGE_SHIFT), 0);
vm->vm_flags |= VM_IO;
-
return ret;
}
/*!
{
unsigned long offset;
- offset = vshare_mem.cpu_addr >> PAGE_SHIFT;
+ offset = (unsigned long)vshare_mem.cpu_addr >> PAGE_SHIFT;
if (vm->vm_pgoff && (vm->vm_pgoff == offset))
return vpu_map_vshare_mem(fp, vm);
return vpu_map_hwregs(fp, vm);
}
-const struct file_operations vpu_fops = {
+static const struct file_operations vpu_fops = {
.owner = THIS_MODULE,
.open = vpu_open,
.unlocked_ioctl = vpu_ioctl,
.mmap = vpu_mmap,
};
+static const struct mxc_vpu_soc_data imx6dl_vpu_data = {
+ .regulator_required = 1,
+ .vpu_pwr_mgmnt = 1,
+ .has_jpu = 1,
+};
+
+static const struct mxc_vpu_soc_data imx6q_vpu_data = {
+ .quirk_subblk_en = 1,
+ .regulator_required = 1,
+ .vpu_pwr_mgmnt = 1,
+ .has_jpu = 1,
+};
+
+static const struct mxc_vpu_soc_data imx53_vpu_data = {
+};
+
+static const struct mxc_vpu_soc_data imx51_vpu_data = {
+ .vpu_pwr_mgmnt = 1,
+};
+
+static const struct of_device_id vpu_of_match[] = {
+ { .compatible = "fsl,imx6dl-vpu", .data = &imx6dl_vpu_data, },
+ { .compatible = "fsl,imx6q-vpu", .data = &imx6q_vpu_data, },
+ { .compatible = "fsl,imx53-vpu", .data = &imx53_vpu_data, },
+ { .compatible = "fsl,imx51-vpu", .data = &imx51_vpu_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
/*!
* This function is called by the driver framework to initialize the vpu device.
* @param dev The device structure for the vpu passed in by the framework.
struct device *temp_class;
struct resource *res;
unsigned long addr = 0;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
struct device_node *np = pdev->dev.of_node;
u32 iramsize;
+ struct vpu_priv *drv_data;
+ const struct of_device_id *of_id = of_match_device(vpu_of_match,
+ &pdev->dev);
+ const struct mxc_vpu_soc_data *soc_data = of_id->data;
- err = of_property_read_u32(np, "iramsize", (u32 *)&iramsize);
- if (!err && iramsize)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
- {
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (drv_data == NULL)
+ return -ENOMEM;
+
+ drv_data->soc_data = soc_data;
+ INIT_LIST_HEAD(&drv_data->users);
+
+ init_waitqueue_head(&vpu_queue);
+
+ err = of_property_read_u32(np, "iramsize", &iramsize);
+ if (!err && iramsize) {
iram_pool = of_get_named_gen_pool(np, "iram", 0);
if (!iram_pool) {
dev_err(&pdev->dev, "iram pool not available\n");
addr = gen_pool_virt_to_phys(iram_pool, iram_base);
}
-#else
- iram_alloc(iramsize, &addr);
-#endif
- if (addr == 0)
- iram.start = iram.end = 0;
- else {
- iram.start = addr;
- iram.end = addr + iramsize - 1;
- }
-#else
-
- vpu_plat = pdev->dev.platform_data;
- if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
- iram_alloc(vpu_plat->iram_size, &addr);
if (addr == 0)
iram.start = iram.end = 0;
else {
iram.start = addr;
- iram.end = addr + vpu_plat->iram_size - 1;
+ iram.end = addr + iramsize - 1;
}
-#endif
vpu_dev = &pdev->dev;
return -ENODEV;
}
phy_vpu_base_addr = res->start;
- vpu_base = ioremap(res->start, res->end - res->start);
+ vpu_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(vpu_base))
+ return PTR_ERR(vpu_base);
vpu_major = register_chrdev(vpu_major, "mxc_vpu", &vpu_fops);
if (vpu_major < 0) {
dev_err(vpu_dev, "vpu: unable to get a major for VPU\n");
- err = -EBUSY;
- goto error;
+ return vpu_major;
}
vpu_class = class_create(THIS_MODULE, "mxc_vpu");
vpu_clk = clk_get(&pdev->dev, "vpu_clk");
if (IS_ERR(vpu_clk)) {
- err = -ENOENT;
+ err = PTR_ERR(vpu_clk);
goto err_out_class;
}
vpu_ipi_irq = platform_get_irq_byname(pdev, "vpu_ipi_irq");
if (vpu_ipi_irq < 0) {
dev_err(vpu_dev, "vpu: unable to get vpu interrupt\n");
- err = -ENXIO;
+ err = vpu_ipi_irq;
goto err_out_class;
}
err = request_irq(vpu_ipi_irq, vpu_ipi_irq_handler, 0, "VPU_CODEC_IRQ",
- (void *)(&vpu_data));
+ &vpu_data);
if (err)
goto err_out_class;
- if (vpu_power_get(true)) {
- if (!(cpu_is_mx51() || cpu_is_mx53())) {
+
+ vpu_regulator = devm_regulator_get(vpu_dev, "pu");
+ if (IS_ERR(vpu_regulator)) {
+ if (drv_data->soc_data->regulator_required) {
dev_err(vpu_dev, "failed to get vpu power\n");
goto err_out_class;
} else {
/* regulator_get will return error on MX5x,
- * just igore it everywhere*/
+ * just igore it everywhere
+ */
dev_warn(vpu_dev, "failed to get vpu power\n");
}
}
-#ifdef MXC_VPU_HAS_JPU
- vpu_jpu_irq = platform_get_irq_byname(pdev, "vpu_jpu_irq");
- if (vpu_jpu_irq < 0) {
- dev_err(vpu_dev, "vpu: unable to get vpu jpu interrupt\n");
- err = -ENXIO;
- free_irq(vpu_ipi_irq, &vpu_data);
- goto err_out_class;
- }
- err = request_irq(vpu_jpu_irq, vpu_jpu_irq_handler, IRQF_TRIGGER_RISING,
- "VPU_JPG_IRQ", (void *)(&vpu_data));
- if (err) {
- free_irq(vpu_ipi_irq, &vpu_data);
- goto err_out_class;
+ platform_set_drvdata(pdev, drv_data);
+
+ if (drv_data->soc_data->has_jpu) {
+ vpu_jpu_irq = platform_get_irq_byname(pdev, "vpu_jpu_irq");
+ if (vpu_jpu_irq < 0) {
+ dev_err(vpu_dev, "vpu: unable to get vpu jpu interrupt\n");
+ err = vpu_jpu_irq;
+ goto err_out_class;
+ }
+ err = request_irq(vpu_jpu_irq, vpu_jpu_irq_handler, IRQF_TRIGGER_RISING,
+ "VPU_JPG_IRQ", &vpu_data);
+ if (err)
+ goto err_out_class;
}
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
pm_runtime_enable(&pdev->dev);
-#endif
vpu_data.workqueue = create_workqueue("vpu_wq");
INIT_WORK(&vpu_data.work, vpu_worker_callback);
mutex_init(&vpu_data.lock);
dev_info(vpu_dev, "VPU initialized\n");
- goto out;
+ return 0;
err_out_class:
device_destroy(vpu_class, MKDEV(vpu_major, 0));
class_destroy(vpu_class);
err_out_chrdev:
unregister_chrdev(vpu_major, "mxc_vpu");
-error:
- iounmap(vpu_base);
-out:
return err;
}
static int vpu_dev_remove(struct platform_device *pdev)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ struct vpu_priv *vpu_data = platform_get_drvdata(pdev);
+
pm_runtime_disable(&pdev->dev);
-#endif
+
free_irq(vpu_ipi_irq, &vpu_data);
#ifdef MXC_VPU_HAS_JPU
free_irq(vpu_jpu_irq, &vpu_data);
#endif
- cancel_work_sync(&vpu_data.work);
- flush_workqueue(vpu_data.workqueue);
- destroy_workqueue(vpu_data.workqueue);
+ cancel_work_sync(&vpu_data->work);
+ flush_workqueue(vpu_data->workqueue);
+ destroy_workqueue(vpu_data->workqueue);
iounmap(vpu_base);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
if (iram.start)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
gen_pool_free(iram_pool, iram_base, iram.end-iram.start+1);
-#else
- iram_free(iram.start, iram.end-iram.start+1);
-#endif
-#else
- if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
- iram_free(iram.start, vpu_plat->iram_size);
-#endif
- vpu_power_get(false);
+ if (vpu_major > 0) {
+ device_destroy(vpu_class, MKDEV(vpu_major, 0));
+ class_destroy(vpu_class);
+ unregister_chrdev(vpu_major, "mxc_vpu");
+ vpu_major = 0;
+ }
+
+ vpu_free_dma_buffer(&bitwork_mem);
+ vpu_free_dma_buffer(&pic_para_mem);
+ vpu_free_dma_buffer(&user_data_mem);
+
+ /* reset VPU state */
+ vpu_power_up();
+ vpu_clk_enable(vpu_data);
+ vpu_reset();
+ vpu_clk_disable(vpu_data);
+ vpu_power_down();
+
+ clk_put(vpu_clk);
return 0;
}
#ifdef CONFIG_PM
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
static int vpu_suspend(struct device *dev)
-#else
-static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
-#endif
{
- int i;
+ struct vpu_priv *vpu_data = dev_get_drvdata(dev);
unsigned long timeout;
- mutex_lock(&vpu_data.lock);
- if (open_count == 0) {
- /* VPU is released (all instances are freed),
- * clock is already off, context is no longer needed,
- * power is already off on MX6,
- * gate power on MX51 */
- if (cpu_is_mx51()) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- if (vpu_plat->pg)
- vpu_plat->pg(1);
-#endif
- }
- } else {
+ mutex_lock(&vpu_data->lock);
+
+ if (open_count) {
/* Wait for vpu go to idle state, suspect vpu cannot be changed
to idle state after about 1 sec */
timeout = jiffies + HZ;
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
while (READ_REG(BIT_BUSY_FLAG)) {
msleep(1);
if (time_after(jiffies, timeout)) {
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- mutex_unlock(&vpu_data.lock);
+ mutex_unlock(&vpu_data->lock);
return -EAGAIN;
}
}
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
-
- /* Make sure clock is disabled before suspend */
- vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
- for (i = 0; i < vpu_clk_usercount; i++) {
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- }
- if (cpu_is_mx53()) {
- mutex_unlock(&vpu_data.lock);
+ if (vpu_data->soc_data->is_mx53) {
+ mutex_unlock(&vpu_data->lock);
return 0;
}
if (bitwork_mem.cpu_addr != 0) {
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
+ int i;
+
/* Save 64 registers from BIT_CODE_BUF_ADDR */
for (i = 0; i < 64; i++)
regBk[i] = READ_REG(BIT_CODE_BUF_ADDR + (i * 4));
pc_before_suspend = READ_REG(BIT_CUR_PC);
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- if (vpu_plat->pg)
- vpu_plat->pg(1);
-#endif
-
+ vpu_clk_disable(vpu_data);
/* If VPU is working before suspend, disable
- * regulator to make usecount right. */
- vpu_power_up(false);
+ * regulator to make usecount right.
+ */
+ vpu_power_down();
}
- mutex_unlock(&vpu_data.lock);
+ mutex_unlock(&vpu_data->lock);
return 0;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
static int vpu_resume(struct device *dev)
-#else
-static int vpu_resume(struct platform_device *pdev)
-#endif
{
int i;
+ struct vpu_priv *vpu_data = dev_get_drvdata(dev);
- mutex_lock(&vpu_data.lock);
- if (open_count == 0) {
- /* VPU is released (all instances are freed),
- * clock should be kept off, context is no longer needed,
- * power should be kept off on MX6,
- * disable power gating on MX51 */
- if (cpu_is_mx51()) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- if (vpu_plat->pg)
- vpu_plat->pg(0);
-#endif
+ mutex_lock(&vpu_data->lock);
+
+ if (open_count) {
+ if (vpu_data->soc_data->is_mx53) {
+ vpu_clk_enable(vpu_data);
+ goto out;
}
- } else {
- if (cpu_is_mx53())
- goto recover_clk;
/* If VPU is working before suspend, enable
- * regulator to make usecount right. */
- vpu_power_up(true);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- if (vpu_plat->pg)
- vpu_plat->pg(0);
-#endif
+ * regulator to make usecount right.
+ */
+ vpu_power_up();
- if (bitwork_mem.cpu_addr != 0) {
- u32 *p = (u32 *) bitwork_mem.cpu_addr;
+ if (bitwork_mem.cpu_addr != NULL) {
+ u32 *p = bitwork_mem.cpu_addr;
u32 data, pc;
u16 data_hi;
u16 data_lo;
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
+ vpu_clk_enable(vpu_data);
pc = READ_REG(BIT_CUR_PC);
if (pc) {
dev_warn(vpu_dev, "Not power off after suspend (PC=0x%x)\n", pc);
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- goto recover_clk;
+ goto out;
}
/* Restore registers */
WRITE_REG(0x0, BIT_RESET_CTRL);
WRITE_REG(0x0, BIT_CODE_RUN);
/* MX6 RTL has a bug not to init MBC_SET_SUBBLK_EN on reset */
-#ifdef CONFIG_SOC_IMX6Q
- WRITE_REG(0x0, MBC_SET_SUBBLK_EN);
-#endif
+ if (vpu_data->soc_data->quirk_subblk_en)
+ WRITE_REG(0x0, MBC_SET_SUBBLK_EN);
/*
* Re-load boot code, from the codebuffer in external RAM.
} else {
dev_warn(vpu_dev, "PC=0 before suspend\n");
}
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- }
-
-recover_clk:
- /* Recover vpu clock */
- for (i = 0; i < vpu_clk_usercount; i++) {
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
}
}
-
- mutex_unlock(&vpu_data.lock);
- return 0;
-}
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-static int vpu_runtime_suspend(struct device *dev)
-{
- release_bus_freq(BUS_FREQ_HIGH);
- return 0;
-}
-
-static int vpu_runtime_resume(struct device *dev)
-{
- request_bus_freq(BUS_FREQ_HIGH);
+out:
+ mutex_unlock(&vpu_data->lock);
return 0;
}
-static const struct dev_pm_ops vpu_pm_ops = {
- SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
-};
-#endif
-
+static SIMPLE_DEV_PM_OPS(vpu_pm_ops, vpu_suspend, vpu_resume);
+#define VPU_PM_OPS &vpu_pm_ops
#else
-#define vpu_suspend NULL
-#define vpu_resume NULL
-#endif /* !CONFIG_PM */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
-static const struct of_device_id vpu_of_match[] = {
- { .compatible = "fsl,imx6-vpu", },
- {/* sentinel */}
-};
-MODULE_DEVICE_TABLE(of, vpu_of_match);
-#endif
+#define VPU_PM_OPS NULL
+#endif /* !CONFIG_PM */
/*! Driver definition
*
*/
static struct platform_driver mxcvpu_driver = {
.driver = {
- .name = "mxc_vpu",
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
- .of_match_table = vpu_of_match,
-#ifdef CONFIG_PM
- .pm = &vpu_pm_ops,
-#endif
-#endif
- },
+ .name = "mxc_vpu",
+ .of_match_table = vpu_of_match,
+ .pm = VPU_PM_OPS,
+ },
.probe = vpu_dev_probe,
.remove = vpu_dev_remove,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- .suspend = vpu_suspend,
- .resume = vpu_resume,
-#endif
};
-static int __init vpu_init(void)
-{
- int ret = platform_driver_register(&mxcvpu_driver);
-
- init_waitqueue_head(&vpu_queue);
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
- memblock_analyze();
- top_address_DRAM = memblock_end_of_DRAM_with_reserved();
-#endif
-
- return ret;
-}
-
-static void __exit vpu_exit(void)
-{
- if (vpu_major > 0) {
- device_destroy(vpu_class, MKDEV(vpu_major, 0));
- class_destroy(vpu_class);
- unregister_chrdev(vpu_major, "mxc_vpu");
- vpu_major = 0;
- }
-
- vpu_free_dma_buffer(&bitwork_mem);
- vpu_free_dma_buffer(&pic_para_mem);
- vpu_free_dma_buffer(&user_data_mem);
-
- /* reset VPU state */
- vpu_power_up(true);
- clk_prepare(vpu_clk);
- clk_enable(vpu_clk);
- vpu_reset();
- clk_disable(vpu_clk);
- clk_unprepare(vpu_clk);
- vpu_power_up(false);
-
- clk_put(vpu_clk);
-
- platform_driver_unregister(&mxcvpu_driver);
- return;
-}
+module_platform_driver(mxcvpu_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
MODULE_LICENSE("GPL");
-
-module_init(vpu_init);
-module_exit(vpu_exit);
FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
/* FLEXCAN interrupt flag register (IFLAG) bits */
-#define FLEXCAN_RESERVED_BUF_ID 8
-#define FLEXCAN_TX_BUF_ID 13
+#define FLEXCAN_TX_BUF_ID 8
#define FLEXCAN_IFLAG_BUF(x) BIT(x)
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
*/
#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */
-#define FLEXCAN_HAS_ERR005829 BIT(3) /* have errata ERR005829 */
/* Structure of the message buffer */
struct flexcan_mb {
};
static struct flexcan_devtype_data fsl_imx28_devtype_data;
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
- .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_ERR005829,
+ .features = FLEXCAN_HAS_V10_FEATURES,
};
static const struct can_bittiming_const flexcan_bittiming_const = {
flexcan_write(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
flexcan_write(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
- if (priv->devtype_data->features & FLEXCAN_HAS_ERR005829) {
- writel(0x0, ®s->cantxfg[FLEXCAN_RESERVED_BUF_ID].can_ctrl);
- writel(0x0, ®s->cantxfg[FLEXCAN_RESERVED_BUF_ID].can_ctrl);
- }
-
return NETDEV_TX_OK;
}
struct napi_struct napi;
int csum_flags;
- int phy_reset_gpio;
-
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
unsigned long last_overflow_check;
struct mmc_data *data)
{
struct scatterlist *sg;
- struct hif_scatter_item *scat_list;
int i;
data->blksz = HIF_MBOX_BLOCK_SIZE;
sg = scat_req->sgentries;
sg_init_table(sg, scat_req->scat_entries);
- scat_list = &scat_req->scat_list[0];
-
/* assemble SG list */
- for (i = 0; i < scat_req->scat_entries; i++, sg++, scat_list++) {
+ for (i = 0; i < scat_req->scat_entries; i++, sg++) {
ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n",
- i, scat_list->buf, scat_list->len);
+ i, scat_req->scat_list[i].buf,
+ scat_req->scat_list[i].len);
- sg_set_buf(sg, scat_list->buf, scat_list->len);
+ sg_set_buf(sg, scat_req->scat_list[i].buf,
+ scat_req->scat_list[i].len);
}
/* set scatter-gather table for request */
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER);
}
-static void exynos_pcie_power_on_phy(struct pcie_port *pp)
-{
- u32 val;
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER);
- val &= ~PCIE_PHY_COMMON_PD_CMN;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_COMMON_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV0_POWER);
- val &= ~PCIE_PHY_TRSV0_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV0_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV1_POWER);
- val &= ~PCIE_PHY_TRSV1_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV1_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV2_POWER);
- val &= ~PCIE_PHY_TRSV2_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV2_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV3_POWER);
- val &= ~PCIE_PHY_TRSV3_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER);
-}
-
-static void exynos_pcie_power_off_phy(struct pcie_port *pp)
-{
- u32 val;
- struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER);
- val |= PCIE_PHY_COMMON_PD_CMN;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_COMMON_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV0_POWER);
- val |= PCIE_PHY_TRSV0_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV0_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV1_POWER);
- val |= PCIE_PHY_TRSV1_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV1_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV2_POWER);
- val |= PCIE_PHY_TRSV2_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV2_POWER);
-
- val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV3_POWER);
- val |= PCIE_PHY_TRSV3_PD_TSV;
- exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER);
-}
-
static void exynos_pcie_init_phy(struct pcie_port *pp)
{
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
#include <linux/device.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
return dt_remember_or_free_map(p, statename, NULL, map, 1);
}
-static int dt_gpio_assert_pinctrl(struct pinctrl *p)
-{
- struct device_node *np = p->dev->of_node;
- enum of_gpio_flags flags;
- int gpio;
- int index = 0;
- int ret;
-
- if (!of_find_property(np, "pinctrl-assert-gpios", NULL))
- return 0; /* Missing the property, so nothing to be done */
-
- for (;; index++) {
- gpio = of_get_named_gpio_flags(np, "pinctrl-assert-gpios",
- index, &flags);
- if (gpio < 0)
- break; /* End of the phandle list */
-
- if (!gpio_is_valid(gpio))
- return -EINVAL;
-
- ret = devm_gpio_request_one(p->dev, gpio, GPIOF_OUT_INIT_LOW,
- NULL);
- if (ret < 0)
- return ret;
-
- if (flags & OF_GPIO_ACTIVE_LOW)
- continue;
-
- if (gpio_cansleep(gpio))
- gpio_set_value_cansleep(gpio, 1);
- else
- gpio_set_value(gpio, 1);
- }
-
- return 0;
-}
-
int pinctrl_dt_to_map(struct pinctrl *p)
{
struct device_node *np = p->dev->of_node;
return 0;
}
- ret = dt_gpio_assert_pinctrl(p);
- if (ret) {
- dev_dbg(p->dev, "failed to assert pinctrl setting: %d\n", ret);
- return ret;
- }
-
/* We may store pointers to property names within the node */
of_node_get(np);
pins based on the status of charger connections with interrupt
handlers.
-config SABRESD_MAX8903
- tristate "Sabresd Board Battery DC-DC Charger for USB and Adapter Power"
- depends on GENERIC_HARDIRQS && TOUCHSCREEN_MAX11801
- help
- Say Y to enable support for the MAX8903 DC-DC charger and sysfs on
- sabresd board.The driver supports controlling charger and battery
- based on the status of charger connections with interrupt handlers.
-
config CHARGER_TWL4030
tristate "OMAP TWL4030 BCI charger driver"
depends on TWL4030_CORE
Say Y to enable support for the battery and AC power in the
Goldfish emulator.
-config IMX6_USB_CHARGER
- bool "Freescale imx6 USB Charger"
- depends on SOC_IMX6Q || SOC_IMX6SL
- help
- Say Y to enable Freescale imx6 USB Charger Detect.
-
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
-obj-$(CONFIG_SABRESD_MAX8903) += sabresd_battery.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_POWER_RESET) += reset/
-obj-$(CONFIG_IMX6_USB_CHARGER) += imx6_usb_charger.o
+++ /dev/null
-/*
- * Copyright (C) 2013 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
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/power/imx6_usb_charger.h>
-#include <linux/regmap.h>
-
-#define HW_ANADIG_REG_3P0_SET (0x00000124)
-#define HW_ANADIG_REG_3P0_CLR (0x00000128)
-#define BM_ANADIG_REG_3P0_ENABLE_ILIMIT 0x00000004
-#define BM_ANADIG_REG_3P0_ENABLE_LINREG 0x00000001
-
-#define HW_ANADIG_USB1_CHRG_DETECT_SET (0x000001b4)
-#define HW_ANADIG_USB1_CHRG_DETECT_CLR (0x000001b8)
-
-#define BM_ANADIG_USB1_CHRG_DETECT_EN_B 0x00100000
-#define BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B 0x00080000
-#define BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT 0x00040000
-
-#define HW_ANADIG_USB1_VBUS_DET_STAT (0x000001c0)
-
-#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID 0x00000008
-
-#define HW_ANADIG_USB1_CHRG_DET_STAT (0x000001d0)
-
-#define BM_ANADIG_USB1_CHRG_DET_STAT_DM_STATE 0x00000004
-#define BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED 0x00000002
-#define BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT 0x00000001
-
-static char *imx6_usb_charger_supplied_to[] = {
- "imx6_usb_charger",
-};
-
-static enum power_supply_property imx6_usb_charger_power_props[] = {
- POWER_SUPPLY_PROP_PRESENT, /* Charger detected */
- POWER_SUPPLY_PROP_ONLINE, /* VBUS online */
- POWER_SUPPLY_PROP_CURRENT_MAX, /* Maximum current in mA */
-};
-
-static int imx6_usb_charger_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct usb_charger *charger =
- container_of(psy, struct usb_charger, psy);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = charger->present;
- break;
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = charger->online;
- break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = charger->max_current;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static void disable_charger_detector(struct regmap *regmap)
-{
- regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_SET,
- BM_ANADIG_USB1_CHRG_DETECT_EN_B |
- BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
-}
-
-static void disable_current_limiter(struct regmap *regmap)
-{
- /* Disable the vdd3p0 current limiter */
- regmap_write(regmap, HW_ANADIG_REG_3P0_CLR,
- BM_ANADIG_REG_3P0_ENABLE_ILIMIT);
-}
-
-/* Return value if the charger is present */
-static int imx6_usb_charger_detect(struct usb_charger *charger)
-{
- struct regmap *regmap = charger->anatop;
- u32 val;
- int i, data_pin_contact_count = 0;
-
- /* Enable the vdd3p0 curret limiter */
- regmap_write(regmap, HW_ANADIG_REG_3P0_SET,
- BM_ANADIG_REG_3P0_ENABLE_LINREG |
- BM_ANADIG_REG_3P0_ENABLE_ILIMIT);
-
- /* check if vbus is valid */
- regmap_read(regmap, HW_ANADIG_USB1_VBUS_DET_STAT, &val);
- if (!(val & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
- dev_err(charger->dev, "vbus is error\n");
- disable_current_limiter(regmap);
- return -EINVAL;
- }
-
- /* Enable charger detector */
- regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_CLR,
- BM_ANADIG_USB1_CHRG_DETECT_EN_B);
- /*
- * - Do not check whether a charger is connected to the USB port
- * - Check whether the USB plug has been in contact with each other
- */
- regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_SET,
- BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
- BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
-
- /* Check if plug is connected */
- for (i = 0; i < 100; i = i + 1) {
- regmap_read(regmap, HW_ANADIG_USB1_CHRG_DET_STAT, &val);
- if (val & BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
- if (data_pin_contact_count++ > 5)
- /* Data pin makes contact */
- break;
- } else {
- msleep(20);
- }
- }
-
- if (i == 100) {
- dev_err(charger->dev,
- "VBUS is coming from a dedicated power supply.\n");
- disable_current_limiter(regmap);
- disable_charger_detector(regmap);
- return -ENXIO;
- }
-
- /*
- * - Do check whether a charger is connected to the USB port
- * - Do not Check whether the USB plug has been in contact with
- * each other
- */
- regmap_write(regmap, HW_ANADIG_USB1_CHRG_DETECT_CLR,
- BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
- BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
- msleep(45);
-
- /* Check if it is a charger */
- regmap_read(regmap, HW_ANADIG_USB1_CHRG_DET_STAT, &val);
- if (!(val & BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
- dev_dbg(charger->dev, "It is a stardard downstream port\n");
- charger->psy.type = POWER_SUPPLY_TYPE_USB;
- charger->max_current = 500;
- disable_charger_detector(regmap);
- } else {
- /* It is a charger */
- disable_charger_detector(regmap);
- msleep(45);
- }
-
- disable_current_limiter(regmap);
-
- return 0;
-}
-
-/*
- * imx6_usb_vbus_connect - inform about VBUS connection
- * @charger: the usb charger
- *
- * Inform the charger VBUS is connected, vbus detect supplier should call it.
- * Besides, the USB device controller is expected to keep the dataline
- * pullups disabled.
- */
-int imx6_usb_vbus_connect(struct usb_charger *charger)
-{
- int ret;
-
- charger->online = 1;
-
- mutex_lock(&charger->lock);
-
- /* Start the 1st period charger detection. */
- ret = imx6_usb_charger_detect(charger);
- if (ret)
- dev_err(charger->dev,
- "Error occurs during detection: %d\n",
- ret);
- else
- charger->present = 1;
-
- mutex_unlock(&charger->lock);
-
- return ret;
-}
-EXPORT_SYMBOL(imx6_usb_vbus_connect);
-
-/*
- * It must be called after dp is pulled up (from USB controller driver),
- * That is used to differentiate DCP and CDP
- */
-int imx6_usb_charger_detect_post(struct usb_charger *charger)
-{
- struct regmap *regmap = charger->anatop;
- int val;
-
- mutex_lock(&charger->lock);
-
- msleep(40);
-
- regmap_read(regmap, HW_ANADIG_USB1_CHRG_DET_STAT, &val);
- if (val & BM_ANADIG_USB1_CHRG_DET_STAT_DM_STATE) {
- dev_dbg(charger->dev, "It is a dedicate charging port\n");
- charger->psy.type = POWER_SUPPLY_TYPE_USB_DCP;
- charger->max_current = 1500;
- } else {
- dev_dbg(charger->dev, "It is a charging downstream port\n");
- charger->psy.type = POWER_SUPPLY_TYPE_USB_CDP;
- charger->max_current = 900;
- }
-
- power_supply_changed(&charger->psy);
-
- mutex_unlock(&charger->lock);
-
- return 0;
-}
-EXPORT_SYMBOL(imx6_usb_charger_detect_post);
-
-/*
- * imx6_usb_vbus_disconnect - inform about VBUS disconnection
- * @charger: the usb charger
- *
- * Inform the charger that VBUS is disconnected. The charging will be
- * stopped and the charger properties cleared.
- */
-int imx6_usb_vbus_disconnect(struct usb_charger *charger)
-{
- charger->online = 0;
- charger->present = 0;
- charger->max_current = 0;
- charger->psy.type = POWER_SUPPLY_TYPE_MAINS;
-
- power_supply_changed(&charger->psy);
-
- return 0;
-}
-EXPORT_SYMBOL(imx6_usb_vbus_disconnect);
-
-/*
- * imx6_usb_create_charger - create a USB charger
- * @charger: the charger to be initialized
- * @name: name for the power supply
-
- * Registers a power supply for the charger. The USB Controller
- * driver will call this after filling struct usb_charger.
- */
-int imx6_usb_create_charger(struct usb_charger *charger,
- const char *name)
-{
- struct power_supply *psy = &charger->psy;
-
- if (!charger->dev)
- return -EINVAL;
-
- if (name)
- psy->name = name;
- else
- psy->name = "imx6_usb_charger";
-
- charger->bc = BATTERY_CHARGING_SPEC_1_2;
- mutex_init(&charger->lock);
-
- psy->type = POWER_SUPPLY_TYPE_MAINS;
- psy->properties = imx6_usb_charger_power_props;
- psy->num_properties = ARRAY_SIZE(imx6_usb_charger_power_props);
- psy->get_property = imx6_usb_charger_get_property;
- psy->supplied_to = imx6_usb_charger_supplied_to;
- psy->num_supplicants = sizeof(imx6_usb_charger_supplied_to)
- / sizeof(char *);
-
- return power_supply_register(charger->dev, psy);
-}
-EXPORT_SYMBOL(imx6_usb_create_charger);
-
-/*
- * imx6_usb_remove_charger - remove a USB charger
- * @charger: the charger to be removed
- *
- * Unregister the chargers power supply.
- */
-void imx6_usb_remove_charger(struct usb_charger *charger)
-{
- power_supply_unregister(&charger->psy);
-}
-EXPORT_SYMBOL(imx6_usb_remove_charger);
+++ /dev/null
-/*
- * sabresd_battery.c - Maxim 8903 USB/Adapter Charger Driver
- *
- * Copyright (C) 2011 Samsung Electronics
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
- * Based on max8903_charger.c
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/power_supply.h>
-#include <linux/platform_device.h>
-#include <linux/power/sabresd_battery.h>
-#include <linux/slab.h>
-
-#define BATTERY_UPDATE_INTERVAL 5 /*seconds*/
-#define LOW_VOLT_THRESHOLD 2800000
-#define HIGH_VOLT_THRESHOLD 4200000
-#define ADC_SAMPLE_COUNT 6
-
-struct max8903_data {
- struct max8903_pdata *pdata;
- struct device *dev;
- struct power_supply psy;
- struct power_supply usb;
- bool fault;
- bool usb_in;
- bool ta_in;
- bool chg_state;
- struct delayed_work work;
- unsigned int interval;
- unsigned short thermal_raw;
- int voltage_uV;
- int current_uA;
- int battery_status;
- int charger_online;
- int charger_voltage_uV;
- int real_capacity;
- int percent;
- int old_percent;
- int usb_charger_online;
- int first_delay_count;
- struct power_supply bat;
- struct power_supply detect_usb;
-};
-
-typedef struct {
- u32 voltage;
- u32 percent;
-} battery_capacity , *pbattery_capacity;
-
-static int offset_discharger;
-static int offset_charger;
-static int offset_usb_charger;
-
-static battery_capacity chargingTable[] = {
- {4050, 99},
- {4040, 98},
- {4020, 97},
- {4010, 96},
- {3990, 95},
- {3980, 94},
- {3970, 93},
- {3960, 92},
- {3950, 91},
- {3940, 90},
- {3930, 85},
- {3920, 81},
- {3910, 77},
- {3900, 73},
- {3890, 70},
- {3860, 65},
- {3830, 60},
- {3780, 55},
- {3760, 50},
- {3740, 45},
- {3720, 40},
- {3700, 35},
- {3680, 30},
- {3660, 25},
- {3640, 20},
- {3620, 17},
- {3600, 14},
- {3580, 13},
- {3560, 12},
- {3540, 11},
- {3520, 10},
- {3500, 9},
- {3480, 8},
- {3460, 7},
- {3440, 6},
- {3430, 5},
- {3420, 4},
- {3020, 0},
-};
-
-static battery_capacity dischargingTable[] = {
- {4050, 100},
- {4035, 99},
- {4020, 98},
- {4010, 97},
- {4000, 96},
- {3990, 96},
- {3980, 95},
- {3970, 92},
- {3960, 91},
- {3950, 90},
- {3940, 88},
- {3930, 86},
- {3920, 84},
- {3910, 82},
- {3900, 80},
- {3890, 74},
- {3860, 69},
- {3830, 64},
- {3780, 59},
- {3760, 54},
- {3740, 49},
- {3720, 44},
- {3700, 39},
- {3680, 34},
- {3660, 29},
- {3640, 24},
- {3620, 19},
- {3600, 14},
- {3580, 13},
- {3560, 12},
- {3540, 11},
- {3520, 10},
- {3500, 9},
- {3480, 8},
- {3460, 7},
- {3440, 6},
- {3430, 5},
- {3420, 4},
- {3020, 0},
-};
-
-u32 calibrate_battery_capability_percent(struct max8903_data *data)
-{
- u8 i;
- pbattery_capacity pTable;
- u32 tableSize;
-
- if (data->battery_status == POWER_SUPPLY_STATUS_DISCHARGING) {
- pTable = dischargingTable;
- tableSize = sizeof(dischargingTable)/
- sizeof(dischargingTable[0]);
- } else {
- pTable = chargingTable;
- tableSize = sizeof(chargingTable)/
- sizeof(chargingTable[0]);
- }
- for (i = 0; i < tableSize; i++) {
- if (data->voltage_uV >= pTable[i].voltage)
- return pTable[i].percent;
- }
-
- return 0;
-}
-
-static enum power_supply_property max8903_charger_props[] = {
- POWER_SUPPLY_PROP_ONLINE,
-};
-
-static enum power_supply_property max8903_battery_props[] = {
- POWER_SUPPLY_PROP_VOLTAGE_NOW,
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_CAPACITY,
- POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
- POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
- POWER_SUPPLY_PROP_HEALTH,
- POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-};
-
-extern u32 max11801_read_adc(void);
-
-static void max8903_charger_update_status(struct max8903_data *data)
-{
- if (data->ta_in) {
- data->charger_online = 1;
- } else if (data->usb_in) {
- data->usb_charger_online = 1;
- } else {
- data->charger_online = 0;
- data->usb_charger_online = 0;
- }
-
- if (!data->charger_online && !data->usb_charger_online) {
- data->battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
- } else if (gpio_get_value(data->pdata->chg) == 0) {
- data->battery_status = POWER_SUPPLY_STATUS_CHARGING;
- } else if ((data->ta_in || data->usb_in) &&
- gpio_get_value(data->pdata->chg) > 0) {
- if (!data->pdata->feature_flag) {
- if (data->percent >= 99)
- data->battery_status = POWER_SUPPLY_STATUS_FULL;
- else
- data->battery_status =
- POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else {
- data->battery_status = POWER_SUPPLY_STATUS_FULL;
- }
- }
-}
-
-u32 calibration_voltage(struct max8903_data *data)
-{
- u32 voltage_data = 0;
- int i;
- int offset;
-
- if (!data->charger_online && !data->usb_charger_online)
- offset = offset_discharger;
- else if (data->usb_charger_online)
- offset = offset_usb_charger;
- else if (data->charger_online)
- offset = offset_charger;
-
- /* simple average */
- for (i = 0; i < ADC_SAMPLE_COUNT; i++)
- voltage_data += max11801_read_adc()-offset;
- voltage_data = voltage_data / ADC_SAMPLE_COUNT;
- dev_dbg(data->dev, "volt: %d\n", voltage_data);
-
- return voltage_data;
-}
-
-static void max8903_battery_update_status(struct max8903_data *data)
-{
- if (!data->pdata->feature_flag) {
- data->voltage_uV = calibration_voltage(data);
- data->percent = calibrate_battery_capability_percent(data);
- if (data->percent != data->old_percent) {
- data->old_percent = data->percent;
- power_supply_changed(&data->bat);
- }
- /*
- * because boot time gap between led framwork and charger
- * framwork,when system boots with charger attatched,
- * charger led framwork loses the first charger online event,
- * add once extra power_supply_changed can fix this issure
- */
- if (data->first_delay_count < 200) {
- data->first_delay_count = data->first_delay_count + 1;
- power_supply_changed(&data->bat);
- }
- }
-}
-
-static int max8903_battery_get_property(struct power_supply *bat,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct max8903_data *di = container_of(bat, struct max8903_data, bat);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_STATUS:
- val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
- if (gpio_get_value(di->pdata->chg) == 0) {
- di->battery_status = POWER_SUPPLY_STATUS_CHARGING;
- } else if ((di->ta_in || di->usb_in) &&
- gpio_get_value(di->pdata->chg) > 0) {
- if (!di->pdata->feature_flag) {
- if (di->percent >= 99)
- di->battery_status =
- POWER_SUPPLY_STATUS_FULL;
- else
- di->battery_status =
- POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else {
- di->battery_status = POWER_SUPPLY_STATUS_FULL;
- }
- }
- val->intval = di->battery_status;
- return 0;
- default:
- break;
- }
-
- switch (psp) {
- case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- val->intval = di->voltage_uV;
- break;
- case POWER_SUPPLY_PROP_CHARGE_NOW:
- val->intval = 0;
- break;
- case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
- val->intval = HIGH_VOLT_THRESHOLD;
- break;
- case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
- val->intval = LOW_VOLT_THRESHOLD;
- break;
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = 1;
- break;
- case POWER_SUPPLY_PROP_CAPACITY:
- val->intval = di->percent < 0 ? 0 :
- (di->percent > 100 ? 100 : di->percent);
- break;
- case POWER_SUPPLY_PROP_HEALTH:
- val->intval = POWER_SUPPLY_HEALTH_GOOD;
- if (di->fault)
- val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- break;
- case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
- if (di->battery_status == POWER_SUPPLY_STATUS_FULL)
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
- else if (di->percent <= 15)
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
- else
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int max8903_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct max8903_data *data = container_of(psy,
- struct max8903_data, psy);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = 0;
- if (data->ta_in)
- val->intval = 1;
- data->charger_online = val->intval;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int max8903_get_usb_property(struct power_supply *usb,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct max8903_data *data = container_of(usb,
- struct max8903_data, usb);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = 0;
- if (data->usb_in)
- val->intval = 1;
- data->usb_charger_online = val->intval;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static irqreturn_t max8903_dcin(int irq, void *_data)
-{
- struct max8903_data *data = _data;
- struct max8903_pdata *pdata = data->pdata;
- bool ta_in = false;
-
- if (pdata->dok)
- ta_in = gpio_get_value(pdata->dok) ? false : true;
-
- if (ta_in == data->ta_in)
- return IRQ_HANDLED;
-
- data->ta_in = ta_in;
- dev_info(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
- "Connected" : "Disconnected");
- max8903_charger_update_status(data);
- power_supply_changed(&data->psy);
- power_supply_changed(&data->bat);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t max8903_usbin(int irq, void *_data)
-{
- struct max8903_data *data = _data;
- struct max8903_pdata *pdata = data->pdata;
- bool usb_in = false;
-
- if (pdata->uok)
- usb_in = gpio_get_value(pdata->uok) ? false : true;
- if (usb_in == data->usb_in)
- return IRQ_HANDLED;
- data->usb_in = usb_in;
- dev_info(data->dev, "USB Charger %s.\n", usb_in ?
- "Connected" : "Disconnected");
- max8903_charger_update_status(data);
- power_supply_changed(&data->bat);
- power_supply_changed(&data->usb);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t max8903_fault(int irq, void *_data)
-{
- struct max8903_data *data = _data;
- struct max8903_pdata *pdata = data->pdata;
- bool fault;
-
- fault = gpio_get_value(pdata->flt) ? false : true;
-
- if (fault == data->fault)
- return IRQ_HANDLED;
- data->fault = fault;
-
- if (fault)
- dev_err(data->dev, "Charger suffers a fault and stops.\n");
- else
- dev_err(data->dev, "Charger recovered from a fault.\n");
- max8903_charger_update_status(data);
- power_supply_changed(&data->psy);
- power_supply_changed(&data->bat);
- power_supply_changed(&data->usb);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t max8903_chg(int irq, void *_data)
-{
- struct max8903_data *data = _data;
- struct max8903_pdata *pdata = data->pdata;
- int chg_state;
-
- chg_state = gpio_get_value(pdata->chg) ? false : true;
-
- if (chg_state == data->chg_state)
- return IRQ_HANDLED;
- data->chg_state = chg_state;
- max8903_charger_update_status(data);
- power_supply_changed(&data->psy);
- power_supply_changed(&data->bat);
- power_supply_changed(&data->usb);
-
- return IRQ_HANDLED;
-}
-
-static void max8903_battery_work(struct work_struct *work)
-{
- struct max8903_data *data;
-
- data = container_of(work, struct max8903_data, work.work);
- data->interval = HZ * BATTERY_UPDATE_INTERVAL;
-
- max8903_charger_update_status(data);
- max8903_battery_update_status(data);
- dev_dbg(data->dev, "battery voltage: %4d mV\n", data->voltage_uV);
- dev_dbg(data->dev, "charger online status: %d\n",
- data->charger_online);
- dev_dbg(data->dev, "battery status : %d\n" , data->battery_status);
- dev_dbg(data->dev, "battery capacity percent: %3d\n", data->percent);
- dev_dbg(data->dev, "data->usb_in: %x , data->ta_in: %x\n",
- data->usb_in, data->ta_in);
- /* reschedule for the next time */
- schedule_delayed_work(&data->work, data->interval);
-}
-
-static ssize_t max8903_voltage_offset_discharger_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "read offset_discharger:%04d\n",
- offset_discharger);
-}
-
-static ssize_t max8903_voltage_offset_discharger_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- int ret;
- unsigned long data;
-
- ret = strict_strtoul(buf, 10, &data);
- offset_discharger = (int)data;
- pr_info("read offset_discharger:%04d\n", offset_discharger);
-
- return count;
-}
-
-static ssize_t max8903_voltage_offset_charger_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "read offset_charger:%04d\n",
- offset_charger);
-}
-
-static ssize_t max8903_voltage_offset_charger_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- int ret;
- unsigned long data;
-
- ret = strict_strtoul(buf, 10, &data);
- offset_charger = (int)data;
- pr_info("read offset_charger:%04d\n", offset_charger);
- return count;
-}
-
-static ssize_t max8903_voltage_offset_usb_charger_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "read offset_usb_charger:%04d\n",
- offset_usb_charger);
-}
-
-static ssize_t max8903_voltage_offset_usb_charger_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- int ret;
- unsigned long data;
-
- ret = strict_strtoul(buf, 10, &data);
- offset_usb_charger = (int)data;
- pr_info("read offset_charger:%04d\n", offset_usb_charger);
-
- return count;
-}
-
-static struct device_attribute max8903_discharger_dev_attr = {
- .attr = {
- .name = "max8903_ctl_offset_discharger",
- .mode = S_IRUSR | S_IWUSR,
- },
- .show = max8903_voltage_offset_discharger_show,
- .store = max8903_voltage_offset_discharger_store,
-};
-
-static struct device_attribute max8903_charger_dev_attr = {
- .attr = {
- .name = "max8903_ctl_offset_charger",
- .mode = S_IRUSR | S_IWUSR,
- },
- .show = max8903_voltage_offset_charger_show,
- .store = max8903_voltage_offset_charger_store,
-};
-
-static struct device_attribute max8903_usb_charger_dev_attr = {
- .attr = {
- .name = "max8903_ctl_offset_usb_charger",
- .mode = S_IRUSR | S_IWUSR,
- },
- .show = max8903_voltage_offset_usb_charger_show,
- .store = max8903_voltage_offset_usb_charger_store,
-};
-
-#if defined(CONFIG_OF)
-static const struct of_device_id max8903_dt_ids[] = {
- { .compatible = "fsl,max8903-charger", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, max8903_dt_ids);
-
-static struct max8903_pdata *max8903_of_populate_pdata(
- struct device *dev)
-{
- struct device_node *of_node = dev->of_node;
- struct max8903_pdata *pdata = dev->platform_data;
-
- if (!of_node || pdata)
- return pdata;
-
- pdata = devm_kzalloc(dev, sizeof(struct max8903_pdata),
- GFP_KERNEL);
- if (!pdata)
- return pdata;
-
- if (of_get_property(of_node, "fsl,dcm_always_high", NULL))
- pdata->dcm_always_high = true;
- if (of_get_property(of_node, "fsl,dc_valid", NULL))
- pdata->dc_valid = true;
- if (of_get_property(of_node, "fsl,usb_valid", NULL))
- pdata->usb_valid = true;
- if (of_get_property(of_node, "fsl,adc_disable", NULL))
- pdata->feature_flag = true;
-
- if (pdata->dc_valid) {
- pdata->dok = of_get_named_gpio(of_node, "dok_input", 0);
- if (!gpio_is_valid(pdata->dok)) {
- dev_err(dev, "pin pdata->dok: invalid gpio %d\n", pdata->dok);
- return NULL;
- }
- }
- if (pdata->usb_valid) {
- pdata->uok = of_get_named_gpio(of_node, "uok_input", 0);
- if (!gpio_is_valid(pdata->uok)) {
- dev_err(dev, "pin pdata->uok: invalid gpio %d\n", pdata->uok);
- return NULL;
- }
- }
- pdata->chg = of_get_named_gpio(of_node, "chg_input", 0);
- if (!gpio_is_valid(pdata->chg)) {
- dev_err(dev, "pin pdata->chg: invalid gpio %d\n", pdata->chg);
- return NULL;
- }
- pdata->flt = of_get_named_gpio(of_node, "flt_input", 0);
- if (!gpio_is_valid(pdata->flt)) {
- dev_err(dev, "pin pdata->flt: invalid gpio %d\n", pdata->flt);
- return NULL;
- }
- /* no need check offset without adc converter */
- if (!pdata->feature_flag) {
- if (of_property_read_u32(of_node, "offset-charger",
- &offset_charger))
- dev_err(dev, "Not setting offset-charger in dts!\n");
-
- if (of_property_read_u32(of_node, "offset-discharger",
- &offset_discharger))
- dev_err(dev, "Not setting offset-discharger in dts!\n");
-
- if (of_property_read_u32(of_node, "offset-usb-charger",
- &offset_usb_charger))
- dev_err(dev, "Not setting offset-usb-charger in dts!\n");
- }
-
- return pdata;
-}
-#endif
-
-static int max8903_probe(struct platform_device *pdev)
-{
- struct max8903_data *data;
- struct device *dev = &pdev->dev;
- struct max8903_pdata *pdata = pdev->dev.platform_data;
- int ret = 0;
- int gpio = 0;
- int ta_in = 0;
- int usb_in = 0;
- int retval;
-
- data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- pdata = max8903_of_populate_pdata(&pdev->dev);
- if (!pdata)
- return -EINVAL;
- }
-
- data->first_delay_count = 0;
- data->pdata = pdata;
- data->dev = dev;
- data->usb_in = 0;
- data->ta_in = 0;
- platform_set_drvdata(pdev, data);
-
- if (pdata->dc_valid == false && pdata->usb_valid == false) {
- dev_err(dev, "No valid power sources.\n");
- ret = -EINVAL;
- goto err;
- }
- if (pdata->dc_valid) {
- if (pdata->dok && pdata->dcm_always_high) {
- gpio = pdata->dok;
- ret = gpio_request_one(gpio, GPIOF_IN, "max8903-DOK");
- if (ret) {
- dev_err(dev, "request max8903-DOK error!!\n");
- goto err;
- }
- ta_in = gpio_get_value(gpio) ? 0 : 1;
- } else {
- dev_err(dev, "When DC is wired, DOK and DCM should be"
- " wired as well or set dcm always high!\n");
- ret = -EINVAL;
- goto err;
- }
- }
-
- if (pdata->usb_valid) {
- if (pdata->uok) {
- gpio = pdata->uok;
- ret = gpio_request_one(gpio, GPIOF_IN, "max8903-UOK");
- if (ret) {
- dev_err(dev, "request max8903-UOK error!!\n");
- goto err;
- }
- usb_in = gpio_get_value(gpio) ? 0 : 1;
- } else {
- dev_err(dev, "When USB is wired, UOK should be wired"
- " as well.\n");
- ret = -EINVAL;
- goto err;
- }
- }
-
- if (pdata->chg) {
- ret = gpio_request_one(pdata->chg, GPIOF_IN, "max8903-CHG");
- if (ret) {
- dev_err(dev, "request max8903-CHG error!!\n");
- goto err;
- }
- }
-
- if (pdata->flt) {
- ret = gpio_request_one(pdata->flt, GPIOF_IN, "max8903-FLT");
- if (ret) {
- dev_err(dev, "request max8903-FLT error!!\n");
- goto err;
- }
- }
-
- data->fault = false;
- data->ta_in = ta_in;
- data->usb_in = usb_in;
- data->psy.name = "max8903-ac";
- data->psy.type = POWER_SUPPLY_TYPE_MAINS;
- data->psy.get_property = max8903_get_property;
- data->psy.properties = max8903_charger_props;
- data->psy.num_properties = ARRAY_SIZE(max8903_charger_props);
- ret = power_supply_register(dev, &data->psy);
- if (ret) {
- dev_err(dev, "failed: power supply register.\n");
- goto err_psy;
- }
-
- data->usb.name = "max8903-usb";
- data->usb.type = POWER_SUPPLY_TYPE_USB;
- data->usb.get_property = max8903_get_usb_property;
- data->usb.properties = max8903_charger_props;
- data->usb.num_properties = ARRAY_SIZE(max8903_charger_props);
- ret = power_supply_register(dev, &data->usb);
- if (ret) {
- dev_err(dev, "failed: power supply register.\n");
- goto err_psy;
- }
-
- data->bat.name = "max8903-charger";
- data->bat.type = POWER_SUPPLY_TYPE_BATTERY;
- data->bat.properties = max8903_battery_props;
- data->bat.num_properties = ARRAY_SIZE(max8903_battery_props);
- data->bat.get_property = max8903_battery_get_property;
- data->bat.use_for_apm = 1;
- retval = power_supply_register(&pdev->dev, &data->bat);
- if (retval) {
- dev_err(data->dev, "failed to register battery\n");
- goto battery_failed;
- }
-
- INIT_DELAYED_WORK(&data->work, max8903_battery_work);
- schedule_delayed_work(&data->work, data->interval);
-
- if (pdata->dc_valid) {
- ret = request_threaded_irq(gpio_to_irq(pdata->dok), NULL,
- max8903_dcin, IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 DC IN",
- data);
- if (ret) {
- dev_err(dev, "Cannot request irq %d for DC (%d)\n",
- gpio_to_irq(pdata->dok), ret);
- goto err_dc_irq;
- }
- }
-
- if (pdata->usb_valid) {
- ret = request_threaded_irq(gpio_to_irq(pdata->uok), NULL,
- max8903_usbin, IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 USB IN",
- data);
- if (ret) {
- dev_err(dev, "Cannot request irq %d for USB (%d)\n",
- gpio_to_irq(pdata->uok), ret);
- goto err_usb_irq;
- }
- }
-
- if (pdata->flt) {
- ret = request_threaded_irq(gpio_to_irq(pdata->flt), NULL,
- max8903_fault, IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 Fault",
- data);
- if (ret) {
- dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
- gpio_to_irq(pdata->flt), ret);
- goto err_flt_irq;
- }
- }
-
- if (pdata->chg) {
- ret = request_threaded_irq(gpio_to_irq(pdata->chg), NULL,
- max8903_chg, IRQF_TRIGGER_FALLING |
- IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 Status",
- data);
- if (ret) {
- dev_err(dev, "Cannot request irq %d for Status (%d)\n",
- gpio_to_irq(pdata->flt), ret);
- goto err_chg_irq;
- }
- }
-
- ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr);
- if (ret)
- dev_err(&pdev->dev, "create device file failed!\n");
- ret = device_create_file(&pdev->dev, &max8903_charger_dev_attr);
- if (ret)
- dev_err(&pdev->dev, "create device file failed!\n");
- ret = device_create_file(&pdev->dev, &max8903_usb_charger_dev_attr);
- if (ret)
- dev_err(&pdev->dev, "create device file failed!\n");
-
- device_set_wakeup_capable(&pdev->dev, true);
-
- max8903_charger_update_status(data);
- max8903_battery_update_status(data);
-
- return 0;
-err_psy:
- power_supply_unregister(&data->psy);
-battery_failed:
- power_supply_unregister(&data->bat);
-err_usb_irq:
- if (pdata->usb_valid)
- free_irq(gpio_to_irq(pdata->uok), data);
- cancel_delayed_work(&data->work);
-err_dc_irq:
- if (pdata->dc_valid)
- free_irq(gpio_to_irq(pdata->dok), data);
- cancel_delayed_work(&data->work);
-err_flt_irq:
- if (pdata->usb_valid)
- free_irq(gpio_to_irq(pdata->uok), data);
- cancel_delayed_work(&data->work);
-err_chg_irq:
- if (pdata->dc_valid)
- free_irq(gpio_to_irq(pdata->dok), data);
- cancel_delayed_work(&data->work);
-err:
- if (pdata->uok)
- gpio_free(pdata->uok);
- if (pdata->dok)
- gpio_free(pdata->dok);
- if (pdata->flt)
- gpio_free(pdata->flt);
- if (pdata->chg)
- gpio_free(pdata->chg);
- return ret;
-}
-
-static int max8903_remove(struct platform_device *pdev)
-{
- struct max8903_data *data = platform_get_drvdata(pdev);
- if (data) {
- struct max8903_pdata *pdata = data->pdata;
-
- cancel_delayed_work_sync(&data->work);
- power_supply_unregister(&data->psy);
- power_supply_unregister(&data->usb);
- power_supply_unregister(&data->bat);
-
- if (pdata->flt) {
- free_irq(gpio_to_irq(pdata->flt), data);
- gpio_free(pdata->flt);
- }
- if (pdata->usb_valid && pdata->uok) {
- free_irq(gpio_to_irq(pdata->uok), data);
- gpio_free(pdata->uok);
- }
- if (pdata->dc_valid) {
- if (pdata->dok) {
- free_irq(gpio_to_irq(pdata->dok), data);
- gpio_free(pdata->dok);
- } else if (pdata->chg) {
- free_irq(gpio_to_irq(pdata->chg), data);
- gpio_free(pdata->chg);
- }
- }
-
- device_remove_file(&pdev->dev, &max8903_discharger_dev_attr);
- device_remove_file(&pdev->dev, &max8903_charger_dev_attr);
- device_remove_file(&pdev->dev, &max8903_usb_charger_dev_attr);
-
- platform_set_drvdata(pdev, NULL);
- kfree(data);
- }
-
- return 0;
-}
-
-static int max8903_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- struct max8903_data *data = platform_get_drvdata(pdev);
- int irq;
- if (data) {
- struct max8903_pdata *pdata = data->pdata;
- if (pdata) {
- if (pdata->dc_valid && device_may_wakeup(&pdev->dev)) {
- irq = gpio_to_irq(pdata->dok);
- enable_irq_wake(irq);
- }
-
- if (pdata->usb_valid && device_may_wakeup(&pdev->dev)) {
- irq = gpio_to_irq(pdata->uok);
- enable_irq_wake(irq);
- }
- cancel_delayed_work(&data->work);
- }
- }
- return 0;
-}
-
-static int max8903_resume(struct platform_device *pdev)
-{
- struct max8903_data *data = platform_get_drvdata(pdev);
- bool ta_in = false;
- bool usb_in = false;
- int irq;
-
- if (data) {
- struct max8903_pdata *pdata = data->pdata;
-
- if (pdata) {
- if (pdata->dok)
- ta_in = gpio_get_value(pdata->dok) ? false : true;
- if (pdata->uok)
- usb_in = gpio_get_value(pdata->uok) ? false : true;
-
- if (ta_in != data->ta_in) {
- data->ta_in = ta_in;
- dev_info(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
- "Connected" : "Disconnected");
- max8903_charger_update_status(data);
- power_supply_changed(&data->psy);
- }
-
- if (usb_in != data->usb_in) {
- data->usb_in = usb_in;
- dev_info(data->dev, "USB Charger %s.\n", usb_in ?
- "Connected" : "Disconnected");
- max8903_charger_update_status(data);
- power_supply_changed(&data->usb);
- }
-
- if (pdata->dc_valid && device_may_wakeup(&pdev->dev)) {
- irq = gpio_to_irq(pdata->dok);
- disable_irq_wake(irq);
- }
- if (pdata->usb_valid && device_may_wakeup(&pdev->dev)) {
- irq = gpio_to_irq(pdata->uok);
- disable_irq_wake(irq);
- }
-
- schedule_delayed_work(&data->work,
- BATTERY_UPDATE_INTERVAL);
- }
- }
-
- return 0;
-}
-
-static struct platform_driver max8903_driver = {
- .probe = max8903_probe,
- .remove = max8903_remove,
- .suspend = max8903_suspend,
- .resume = max8903_resume,
- .driver = {
- .name = "max8903-charger",
- .owner = THIS_MODULE,
- .of_match_table = max8903_dt_ids,
- },
-};
-module_platform_driver(max8903_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("Sabresd Battery Driver");
-MODULE_ALIAS("sabresd_battery");
if (list_empty(&message->transfers))
return -EINVAL;
- if (list_empty(&message->transfers))
- return -EINVAL;
- if (!message->complete)
- return -EINVAL;
-
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by
return 0;
}
-static const struct thermal_zone_device_ops imx_tz_ops = {
+static struct thermal_zone_device_ops imx_tz_ops = {
.bind = imx_bind,
.unbind = imx_unbind,
.get_temp = imx_get_temp,
/* Disconnect any existing devices under this port */
if (udev) {
- if (hcd->phy && !hdev->parent)
+ if (hcd->phy && !hdev->parent &&
+ !(portstatus & USB_PORT_STAT_CONNECTION))
usb_phy_notify_disconnect(hcd->phy, udev->speed);
usb_disconnect(&port_dev->child);
}
source "drivers/video/fbdev/Kconfig"
endmenu
+source "drivers/video/mxc/Kconfig"
+
source "drivers/video/backlight/Kconfig"
config VGASTATE
obj-y += backlight/
obj-y += fbdev/
+obj-y += mxc/
obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
ifeq ($(CONFIG_OF),y)
--- /dev/null
+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 <http://www.linux-fbdev.org/> 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"
+
+config FB_MXC_LDB
+ tristate "MXC LDB"
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
+
+config FB_MXC_MIPI_DSI
+ tristate "MXC MIPI_DSI"
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
+
+config FB_MXC_TRULY_WVGA_SYNC_PANEL
+ tristate "TRULY WVGA Panel"
+ depends on FB_MXC_SYNC_PANEL
+ depends on FB_MXC_MIPI_DSI
+
+config FB_MXC_HDMI
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
+ depends on I2C
+ tristate "MXC HDMI driver support"
+ select MFD_MXC_HDMI
+ help
+ Driver for the on-chip MXC HDMI controller.
+
+config FB_MXC_EDID
+ depends on FB_MXC && I2C
+ tristate "MXC EDID support"
+ default y
+
+config FB_MXC_EINK_PANEL
+ depends on FB_MXC
+ depends on DMA_ENGINE
+ select FB_DEFERRED_IO
+ tristate "E-Ink Panel Framebuffer"
+
+config FB_MXC_EINK_AUTO_UPDATE_MODE
+ bool "E-Ink Auto-update Mode Support"
+ default n
+ depends on FB_MXC_EINK_PANEL
+
+config FB_MXS_SII902X
+ tristate "Si Image SII9022 DVI/HDMI Interface Chip"
+ depends on FB_MXS && I2C
+
+config HANNSTAR_CABC
+ tristate "Hannstar CABC function"
+ help
+ Say yes here to support switching on/off Hannstar CABC
+ function. This function turns backlight density of a
+ display panel automatically according to the content
+ shown on the panel.
--- /dev/null
+obj-$(CONFIG_FB_MXC_LDB) += ldb.o
+obj-$(CONFIG_FB_MXC_MIPI_DSI) += mipi_dsi.o
+obj-$(CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL) += mxcfb_hx8369_wvga.o
+obj-$(CONFIG_FB_MXC_HDMI) += mxc_hdmi.o
+obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o
+obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o
+obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o
+obj-$(CONFIG_FB_MXS_SII902X) += mxsfb_sii902x.o
+obj-$(CONFIG_HANNSTAR_CABC) += hannstar_cabc.o
--- /dev/null
+/*
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*!
+ * @file mxc_ldb.c
+ *
+ * @brief This file contains the LDB driver device interface and fops
+ * functions.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/mxcfb.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
+#include "mxc_dispdrv.h"
+
+#define DISPDRV_LDB "ldb"
+
+#define LDB_BGREF_RMODE_MASK 0x00008000
+#define LDB_BGREF_RMODE_INT 0x00008000
+#define LDB_BGREF_RMODE_EXT 0x0
+
+#define LDB_DI1_VS_POL_MASK 0x00000400
+#define LDB_DI1_VS_POL_ACT_LOW 0x00000400
+#define LDB_DI1_VS_POL_ACT_HIGH 0x0
+#define LDB_DI0_VS_POL_MASK 0x00000200
+#define LDB_DI0_VS_POL_ACT_LOW 0x00000200
+#define LDB_DI0_VS_POL_ACT_HIGH 0x0
+
+#define LDB_BIT_MAP_CH1_MASK 0x00000100
+#define LDB_BIT_MAP_CH1_JEIDA 0x00000100
+#define LDB_BIT_MAP_CH1_SPWG 0x0
+#define LDB_BIT_MAP_CH0_MASK 0x00000040
+#define LDB_BIT_MAP_CH0_JEIDA 0x00000040
+#define LDB_BIT_MAP_CH0_SPWG 0x0
+
+#define LDB_DATA_WIDTH_CH1_MASK 0x00000080
+#define LDB_DATA_WIDTH_CH1_24 0x00000080
+#define LDB_DATA_WIDTH_CH1_18 0x0
+#define LDB_DATA_WIDTH_CH0_MASK 0x00000020
+#define LDB_DATA_WIDTH_CH0_24 0x00000020
+#define LDB_DATA_WIDTH_CH0_18 0x0
+
+#define LDB_CH1_MODE_MASK 0x0000000C
+#define LDB_CH1_MODE_EN_TO_DI1 0x0000000C
+#define LDB_CH1_MODE_EN_TO_DI0 0x00000004
+#define LDB_CH1_MODE_DISABLE 0x0
+#define LDB_CH0_MODE_MASK 0x00000003
+#define LDB_CH0_MODE_EN_TO_DI1 0x00000003
+#define LDB_CH0_MODE_EN_TO_DI0 0x00000001
+#define LDB_CH0_MODE_DISABLE 0x0
+
+#define LDB_SPLIT_MODE_EN 0x00000010
+
+enum {
+ IMX6_LDB,
+};
+
+enum {
+ LDB_IMX6 = 1,
+};
+
+struct fsl_mxc_ldb_platform_data {
+ int devtype;
+ u32 ext_ref;
+#define LDB_SPL_DI0 1
+#define LDB_SPL_DI1 2
+#define LDB_DUL_DI0 3
+#define LDB_DUL_DI1 4
+#define LDB_SIN0 5
+#define LDB_SIN1 6
+#define LDB_SEP0 7
+#define LDB_SEP1 8
+ int mode;
+ int ipu_id;
+ int disp_id;
+
+ /*only work for separate mode*/
+ int sec_ipu_id;
+ int sec_disp_id;
+};
+
+struct ldb_data {
+ struct platform_device *pdev;
+ struct mxc_dispdrv_handle *disp_ldb;
+ uint32_t *reg;
+ uint32_t *control_reg;
+ uint32_t *gpr3_reg;
+ uint32_t control_reg_data;
+ struct regulator *lvds_bg_reg;
+ int mode;
+ bool inited;
+ struct ldb_setting {
+ struct clk *di_clk;
+ struct clk *ldb_di_clk;
+ struct clk *div_3_5_clk;
+ struct clk *div_7_clk;
+ struct clk *div_sel_clk;
+ bool active;
+ bool clk_en;
+ int ipu;
+ int di;
+ uint32_t ch_mask;
+ uint32_t ch_val;
+ } setting[2];
+ struct notifier_block nb;
+};
+
+static int g_ldb_mode;
+
+static struct fb_videomode ldb_modedb[] = {
+ {
+ "LDB-WXGA", 60, 1280, 800, 14065,
+ 40, 40,
+ 10, 3,
+ 80, 10,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,},
+ {
+ "LDB-XGA", 60, 1024, 768, 15385,
+ 220, 40,
+ 21, 7,
+ 60, 10,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,},
+ {
+ "LDB-1080P60", 60, 1920, 1080, 7692,
+ 100, 40,
+ 30, 3,
+ 10, 2,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,},
+};
+static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);
+
+static inline int is_imx6_ldb(struct fsl_mxc_ldb_platform_data *plat_data)
+{
+ return (plat_data->devtype == LDB_IMX6);
+}
+
+static int bits_per_pixel(int pixel_fmt)
+{
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ return 24;
+ break;
+ case IPU_PIX_FMT_BGR666:
+ case IPU_PIX_FMT_RGB666:
+ case IPU_PIX_FMT_LVDS666:
+ return 18;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int valid_mode(int pixel_fmt)
+{
+ return ((pixel_fmt == IPU_PIX_FMT_RGB24) ||
+ (pixel_fmt == IPU_PIX_FMT_BGR24) ||
+ (pixel_fmt == IPU_PIX_FMT_LVDS666) ||
+ (pixel_fmt == IPU_PIX_FMT_RGB666) ||
+ (pixel_fmt == IPU_PIX_FMT_BGR666));
+}
+
+static int parse_ldb_mode(char *mode)
+{
+ int ldb_mode;
+
+ if (!strcmp(mode, "spl0"))
+ ldb_mode = LDB_SPL_DI0;
+ else if (!strcmp(mode, "spl1"))
+ ldb_mode = LDB_SPL_DI1;
+ else if (!strcmp(mode, "dul0"))
+ ldb_mode = LDB_DUL_DI0;
+ else if (!strcmp(mode, "dul1"))
+ ldb_mode = LDB_DUL_DI1;
+ else if (!strcmp(mode, "sin0"))
+ ldb_mode = LDB_SIN0;
+ else if (!strcmp(mode, "sin1"))
+ ldb_mode = LDB_SIN1;
+ else if (!strcmp(mode, "sep0"))
+ ldb_mode = LDB_SEP0;
+ else if (!strcmp(mode, "sep1"))
+ ldb_mode = LDB_SEP1;
+ else
+ ldb_mode = -EINVAL;
+
+ return ldb_mode;
+}
+
+#ifndef MODULE
+/*
+ * "ldb=spl0/1" -- split mode on DI0/1
+ * "ldb=dul0/1" -- dual mode on DI0/1
+ * "ldb=sin0/1" -- single mode on LVDS0/1
+ * "ldb=sep0/1" -- separate mode begin from LVDS0/1
+ *
+ * there are two LVDS channels(LVDS0 and LVDS1) which can transfer video
+ * datas, there two channels can be used as split/dual/single/separate mode.
+ *
+ * split mode means display data from DI0 or DI1 will send to both channels
+ * LVDS0+LVDS1.
+ * dual mode means display data from DI0 or DI1 will be duplicated on LVDS0
+ * and LVDS1, it said, LVDS0 and LVDS1 has the same content.
+ * single mode means only work for DI0/DI1->LVDS0 or DI0/DI1->LVDS1.
+ * separate mode means you can make DI0/DI1->LVDS0 and DI0/DI1->LVDS1 work
+ * at the same time.
+ */
+static int __init ldb_setup(char *options)
+{
+ g_ldb_mode = parse_ldb_mode(options);
+ return (g_ldb_mode < 0) ? 0 : 1;
+}
+__setup("ldb=", ldb_setup);
+#endif
+
+static int ldb_get_of_property(struct platform_device *pdev,
+ struct fsl_mxc_ldb_platform_data *plat_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int err;
+ u32 ipu_id, disp_id;
+ u32 sec_ipu_id, sec_disp_id;
+ char *mode;
+ u32 ext_ref;
+
+ err = of_property_read_string(np, "mode", (const char **)&mode);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property mode fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "ext_ref", &ext_ref);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property ext_ref fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "ipu_id", &ipu_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property ipu_id fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "disp_id", &disp_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property disp_id fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "sec_ipu_id", &sec_ipu_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property sec_ipu_id fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "sec_disp_id", &sec_disp_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property sec_disp_id fail\n");
+ return err;
+ }
+
+ plat_data->mode = parse_ldb_mode(mode);
+ plat_data->ext_ref = ext_ref;
+ plat_data->ipu_id = ipu_id;
+ plat_data->disp_id = disp_id;
+ plat_data->sec_ipu_id = sec_ipu_id;
+ plat_data->sec_disp_id = sec_disp_id;
+
+ return err;
+}
+
+static int find_ldb_setting(struct ldb_data *ldb, struct fb_info *fbi)
+{
+ char *id_di[] = {
+ "DISP3 BG",
+ "DISP3 BG - DI1",
+ };
+ char id[16];
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (ldb->setting[i].active) {
+ memset(id, 0, 16);
+ memcpy(id, id_di[ldb->setting[i].di],
+ strlen(id_di[ldb->setting[i].di]));
+ id[4] += ldb->setting[i].ipu;
+ if (!strcmp(id, fbi->fix.id))
+ return i;
+ }
+ }
+ return -EINVAL;
+}
+
+static int ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)
+{
+ uint32_t reg, val;
+ uint32_t pixel_clk, rounded_pixel_clk;
+ struct clk *ldb_clk_parent;
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ int setting_idx, di;
+ int ret;
+
+ setting_idx = find_ldb_setting(ldb, fbi);
+ if (setting_idx < 0)
+ return setting_idx;
+
+ di = ldb->setting[setting_idx].di;
+
+ /* restore channel mode setting */
+ val = readl(ldb->control_reg);
+ val |= ldb->setting[setting_idx].ch_val;
+ writel(val, ldb->control_reg);
+ dev_dbg(&ldb->pdev->dev, "LDB setup, control reg:0x%x\n",
+ readl(ldb->control_reg));
+
+ /* vsync setup */
+ reg = readl(ldb->control_reg);
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) {
+ if (di == 0)
+ reg = (reg & ~LDB_DI0_VS_POL_MASK)
+ | LDB_DI0_VS_POL_ACT_HIGH;
+ else
+ reg = (reg & ~LDB_DI1_VS_POL_MASK)
+ | LDB_DI1_VS_POL_ACT_HIGH;
+ } else {
+ if (di == 0)
+ reg = (reg & ~LDB_DI0_VS_POL_MASK)
+ | LDB_DI0_VS_POL_ACT_LOW;
+ else
+ reg = (reg & ~LDB_DI1_VS_POL_MASK)
+ | LDB_DI1_VS_POL_ACT_LOW;
+ }
+ writel(reg, ldb->control_reg);
+
+ /* clk setup */
+ if (ldb->setting[setting_idx].clk_en)
+ clk_disable_unprepare(ldb->setting[setting_idx].ldb_di_clk);
+ pixel_clk = (PICOS2KHZ(fbi->var.pixclock)) * 1000UL;
+ ldb_clk_parent = clk_get_parent(ldb->setting[setting_idx].ldb_di_clk);
+ if (IS_ERR(ldb_clk_parent)) {
+ dev_err(&ldb->pdev->dev, "get ldb di parent clk fail\n");
+ return PTR_ERR(ldb_clk_parent);
+ }
+ if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1))
+ ret = clk_set_rate(ldb_clk_parent, pixel_clk * 7 / 2);
+ else
+ ret = clk_set_rate(ldb_clk_parent, pixel_clk * 7);
+ if (ret < 0) {
+ dev_err(&ldb->pdev->dev, "set ldb parent clk fail:%d\n", ret);
+ return ret;
+ }
+ rounded_pixel_clk = clk_round_rate(ldb->setting[setting_idx].ldb_di_clk,
+ pixel_clk);
+ dev_dbg(&ldb->pdev->dev, "pixel_clk:%d, rounded_pixel_clk:%d\n",
+ pixel_clk, rounded_pixel_clk);
+ ret = clk_set_rate(ldb->setting[setting_idx].ldb_di_clk,
+ rounded_pixel_clk);
+ if (ret < 0) {
+ dev_err(&ldb->pdev->dev, "set ldb di clk fail:%d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(ldb->setting[setting_idx].ldb_di_clk);
+ if (ret < 0) {
+ dev_err(&ldb->pdev->dev, "enable ldb di clk fail:%d\n", ret);
+ return ret;
+ }
+
+ if (!ldb->setting[setting_idx].clk_en)
+ ldb->setting[setting_idx].clk_en = true;
+
+ return 0;
+}
+
+int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
+{
+ struct ldb_data *ldb = container_of(nb, struct ldb_data, nb);
+ struct fb_event *event = v;
+ struct fb_info *fbi = event->info;
+ int index;
+ uint32_t data;
+
+ index = find_ldb_setting(ldb, fbi);
+ if (index < 0)
+ return 0;
+
+ fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
+ &fbi->modelist);
+
+ if (!fbi->mode) {
+ dev_warn(&ldb->pdev->dev,
+ "LDB: can not find mode for xres=%d, yres=%d\n",
+ fbi->var.xres, fbi->var.yres);
+ if (ldb->setting[index].clk_en) {
+ clk_disable(ldb->setting[index].ldb_di_clk);
+ ldb->setting[index].clk_en = false;
+ data = readl(ldb->control_reg);
+ data &= ~ldb->setting[index].ch_mask;
+ writel(data, ldb->control_reg);
+ }
+ return 0;
+ }
+
+ switch (val) {
+ case FB_EVENT_BLANK:
+ {
+ if (*((int *)event->data) == FB_BLANK_UNBLANK) {
+ if (!ldb->setting[index].clk_en) {
+ clk_enable(ldb->setting[index].ldb_di_clk);
+ ldb->setting[index].clk_en = true;
+ }
+ } else {
+ if (ldb->setting[index].clk_en) {
+ clk_disable(ldb->setting[index].ldb_di_clk);
+ ldb->setting[index].clk_en = false;
+ data = readl(ldb->control_reg);
+ data &= ~ldb->setting[index].ch_mask;
+ writel(data, ldb->control_reg);
+ dev_dbg(&ldb->pdev->dev,
+ "LDB blank, control reg:0x%x\n",
+ readl(ldb->control_reg));
+ }
+ }
+ break;
+ }
+ case FB_EVENT_SUSPEND:
+ if (ldb->setting[index].clk_en) {
+ clk_disable(ldb->setting[index].ldb_di_clk);
+ ldb->setting[index].clk_en = false;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+#define LVDS_MUX_CTL_WIDTH 2
+#define LVDS_MUX_CTL_MASK 3
+#define LVDS0_MUX_CTL_OFFS 6
+#define LVDS1_MUX_CTL_OFFS 8
+#define LVDS0_MUX_CTL_MASK (LVDS_MUX_CTL_MASK << 6)
+#define LVDS1_MUX_CTL_MASK (LVDS_MUX_CTL_MASK << 8)
+#define ROUTE_IPU_DI(ipu, di) (((ipu << 1) | di) & LVDS_MUX_CTL_MASK)
+static int ldb_ipu_ldb_route(int ipu, int di, struct ldb_data *ldb)
+{
+ uint32_t reg;
+ int channel;
+ int shift;
+ int mode = ldb->mode;
+
+ reg = readl(ldb->gpr3_reg);
+ if (mode < LDB_SIN0) {
+ reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ reg |= (ROUTE_IPU_DI(ipu, di) << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU_DI(ipu, di) << LVDS1_MUX_CTL_OFFS);
+ dev_dbg(&ldb->pdev->dev,
+ "Dual/Split mode both channels route to IPU%d-DI%d\n",
+ ipu, di);
+ } else if ((mode == LDB_SIN0) || (mode == LDB_SIN1)) {
+ reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ channel = mode - LDB_SIN0;
+ shift = LVDS0_MUX_CTL_OFFS + channel * LVDS_MUX_CTL_WIDTH;
+ reg |= ROUTE_IPU_DI(ipu, di) << shift;
+ dev_dbg(&ldb->pdev->dev,
+ "Single mode channel %d route to IPU%d-DI%d\n",
+ channel, ipu, di);
+ } else {
+ static bool first = true;
+
+ if (first) {
+ if (mode == LDB_SEP0) {
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ channel = 0;
+ } else {
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ channel = 1;
+ }
+ first = false;
+ } else {
+ if (mode == LDB_SEP0) {
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ channel = 1;
+ } else {
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ channel = 0;
+ }
+ }
+
+ shift = LVDS0_MUX_CTL_OFFS + channel * LVDS_MUX_CTL_WIDTH;
+ reg |= ROUTE_IPU_DI(ipu, di) << shift;
+
+ dev_dbg(&ldb->pdev->dev,
+ "Separate mode channel %d route to IPU%d-DI%d\n",
+ channel, ipu, di);
+ }
+ writel(reg, ldb->gpr3_reg);
+
+ return 0;
+}
+
+static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
+ struct mxc_dispdrv_setting *setting)
+{
+ int ret = 0, i, lvds_channel = 0;
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data;
+ struct resource *res;
+ uint32_t reg, setting_idx;
+ uint32_t ch_mask = 0, ch_val = 0;
+ uint32_t ipu_id, disp_id;
+ char di_clk[] = "ipu1_di0_sel";
+ char ldb_clk[] = "ldb_di0";
+ char div_3_5_clk[] = "di0_div_3_5";
+ char div_7_clk[] = "di0_div_7";
+ char div_sel_clk[] = "di0_div_sel";
+
+ /* if input format not valid, make RGB666 as default*/
+ if (!valid_mode(setting->if_fmt)) {
+ dev_warn(&ldb->pdev->dev, "Input pixel format not valid"
+ " use default RGB666\n");
+ setting->if_fmt = IPU_PIX_FMT_RGB666;
+ }
+
+ if (!ldb->inited) {
+ setting_idx = 0;
+ res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&ldb->pdev->dev, "get iomem fail.\n");
+ return -ENOMEM;
+ }
+
+ ldb->reg = devm_ioremap(&ldb->pdev->dev, res->start,
+ resource_size(res));
+ ldb->control_reg = ldb->reg + 2;
+ ldb->gpr3_reg = ldb->reg + 3;
+
+ /* ipu selected by platform data setting */
+ setting->dev_id = plat_data->ipu_id;
+
+ reg = readl(ldb->control_reg);
+
+ /* refrence resistor select */
+ reg &= ~LDB_BGREF_RMODE_MASK;
+ if (plat_data->ext_ref)
+ reg |= LDB_BGREF_RMODE_EXT;
+ else
+ reg |= LDB_BGREF_RMODE_INT;
+
+ /* TODO: now only use SPWG data mapping for both channel */
+ reg &= ~(LDB_BIT_MAP_CH0_MASK | LDB_BIT_MAP_CH1_MASK);
+ reg |= LDB_BIT_MAP_CH0_SPWG | LDB_BIT_MAP_CH1_SPWG;
+
+ /* channel mode setting */
+ reg &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
+ reg &= ~(LDB_DATA_WIDTH_CH0_MASK | LDB_DATA_WIDTH_CH1_MASK);
+
+ if (bits_per_pixel(setting->if_fmt) == 24)
+ reg |= LDB_DATA_WIDTH_CH0_24 | LDB_DATA_WIDTH_CH1_24;
+ else
+ reg |= LDB_DATA_WIDTH_CH0_18 | LDB_DATA_WIDTH_CH1_18;
+
+ if (g_ldb_mode >= LDB_SPL_DI0)
+ ldb->mode = g_ldb_mode;
+ else
+ ldb->mode = plat_data->mode;
+
+ if ((ldb->mode == LDB_SIN0) || (ldb->mode == LDB_SIN1)) {
+ ret = ldb->mode - LDB_SIN0;
+ if (plat_data->disp_id != ret) {
+ dev_warn(&ldb->pdev->dev,
+ "change IPU DI%d to IPU DI%d for LDB "
+ "channel%d.\n",
+ plat_data->disp_id, ret, ret);
+ plat_data->disp_id = ret;
+ }
+ } else if (((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))
+ && is_imx6_ldb(plat_data)) {
+ if (plat_data->disp_id == plat_data->sec_disp_id) {
+ dev_err(&ldb->pdev->dev,
+ "For LVDS separate mode,"
+ "two DIs should be different!\n");
+ return -EINVAL;
+ }
+
+ if (((!plat_data->disp_id) && (ldb->mode == LDB_SEP1))
+ || ((plat_data->disp_id) &&
+ (ldb->mode == LDB_SEP0))) {
+ dev_dbg(&ldb->pdev->dev,
+ "LVDS separate mode:"
+ "swap DI configuration!\n");
+ ipu_id = plat_data->ipu_id;
+ disp_id = plat_data->disp_id;
+ plat_data->ipu_id = plat_data->sec_ipu_id;
+ plat_data->disp_id = plat_data->sec_disp_id;
+ plat_data->sec_ipu_id = ipu_id;
+ plat_data->sec_disp_id = disp_id;
+ }
+ }
+
+ if (ldb->mode == LDB_SPL_DI0) {
+ reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI0
+ | LDB_CH1_MODE_EN_TO_DI0;
+ setting->disp_id = 0;
+ } else if (ldb->mode == LDB_SPL_DI1) {
+ reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI1
+ | LDB_CH1_MODE_EN_TO_DI1;
+ setting->disp_id = 1;
+ } else if (ldb->mode == LDB_DUL_DI0) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0;
+ setting->disp_id = 0;
+ } else if (ldb->mode == LDB_DUL_DI1) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1;
+ setting->disp_id = 1;
+ } else if (ldb->mode == LDB_SIN0) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ setting->disp_id = plat_data->disp_id;
+ if (setting->disp_id == 0)
+ reg |= LDB_CH0_MODE_EN_TO_DI0;
+ else
+ reg |= LDB_CH0_MODE_EN_TO_DI1;
+ ch_mask = LDB_CH0_MODE_MASK;
+ ch_val = reg & LDB_CH0_MODE_MASK;
+ } else if (ldb->mode == LDB_SIN1) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ setting->disp_id = plat_data->disp_id;
+ if (setting->disp_id == 0)
+ reg |= LDB_CH1_MODE_EN_TO_DI0;
+ else
+ reg |= LDB_CH1_MODE_EN_TO_DI1;
+ ch_mask = LDB_CH1_MODE_MASK;
+ ch_val = reg & LDB_CH1_MODE_MASK;
+ } else { /* separate mode*/
+ setting->disp_id = plat_data->disp_id;
+
+ /* first output is LVDS0 or LVDS1 */
+ if (ldb->mode == LDB_SEP0)
+ lvds_channel = 0;
+ else
+ lvds_channel = 1;
+
+ reg &= ~LDB_SPLIT_MODE_EN;
+
+ if ((lvds_channel == 0) && (setting->disp_id == 0))
+ reg |= LDB_CH0_MODE_EN_TO_DI0;
+ else if ((lvds_channel == 0) && (setting->disp_id == 1))
+ reg |= LDB_CH0_MODE_EN_TO_DI1;
+ else if ((lvds_channel == 1) && (setting->disp_id == 0))
+ reg |= LDB_CH1_MODE_EN_TO_DI0;
+ else
+ reg |= LDB_CH1_MODE_EN_TO_DI1;
+ ch_mask = lvds_channel ? LDB_CH1_MODE_MASK :
+ LDB_CH0_MODE_MASK;
+ ch_val = reg & ch_mask;
+
+ if (bits_per_pixel(setting->if_fmt) == 24) {
+ if (lvds_channel == 0)
+ reg &= ~LDB_DATA_WIDTH_CH1_24;
+ else
+ reg &= ~LDB_DATA_WIDTH_CH0_24;
+ } else {
+ if (lvds_channel == 0)
+ reg &= ~LDB_DATA_WIDTH_CH1_18;
+ else
+ reg &= ~LDB_DATA_WIDTH_CH0_18;
+ }
+ }
+
+ writel(reg, ldb->control_reg);
+ if (ldb->mode < LDB_SIN0) {
+ ch_mask = LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK;
+ ch_val = reg & (LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
+ }
+ } else { /* second time for separate mode */
+ if ((ldb->mode == LDB_SPL_DI0) ||
+ (ldb->mode == LDB_SPL_DI1) ||
+ (ldb->mode == LDB_DUL_DI0) ||
+ (ldb->mode == LDB_DUL_DI1) ||
+ (ldb->mode == LDB_SIN0) ||
+ (ldb->mode == LDB_SIN1)) {
+ dev_err(&ldb->pdev->dev, "for second ldb disp"
+ "ldb mode should in separate mode\n");
+ return -EINVAL;
+ }
+
+ setting_idx = 1;
+ if (is_imx6_ldb(plat_data)) {
+ setting->dev_id = plat_data->sec_ipu_id;
+ setting->disp_id = plat_data->sec_disp_id;
+ } else {
+ setting->dev_id = plat_data->ipu_id;
+ setting->disp_id = !plat_data->disp_id;
+ }
+ if (setting->disp_id == ldb->setting[0].di) {
+ dev_err(&ldb->pdev->dev, "Err: for second ldb disp in"
+ "separate mode, DI should be different!\n");
+ return -EINVAL;
+ }
+
+ /* second output is LVDS0 or LVDS1 */
+ if (ldb->mode == LDB_SEP0)
+ lvds_channel = 1;
+ else
+ lvds_channel = 0;
+
+ reg = readl(ldb->control_reg);
+ if ((lvds_channel == 0) && (setting->disp_id == 0))
+ reg |= LDB_CH0_MODE_EN_TO_DI0;
+ else if ((lvds_channel == 0) && (setting->disp_id == 1))
+ reg |= LDB_CH0_MODE_EN_TO_DI1;
+ else if ((lvds_channel == 1) && (setting->disp_id == 0))
+ reg |= LDB_CH1_MODE_EN_TO_DI0;
+ else
+ reg |= LDB_CH1_MODE_EN_TO_DI1;
+ ch_mask = lvds_channel ? LDB_CH1_MODE_MASK :
+ LDB_CH0_MODE_MASK;
+ ch_val = reg & ch_mask;
+
+ if (bits_per_pixel(setting->if_fmt) == 24) {
+ if (lvds_channel == 0)
+ reg |= LDB_DATA_WIDTH_CH0_24;
+ else
+ reg |= LDB_DATA_WIDTH_CH1_24;
+ } else {
+ if (lvds_channel == 0)
+ reg |= LDB_DATA_WIDTH_CH0_18;
+ else
+ reg |= LDB_DATA_WIDTH_CH1_18;
+ }
+ writel(reg, ldb->control_reg);
+ }
+
+ /* get clocks */
+ if (is_imx6_ldb(plat_data) &&
+ ((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))) {
+ ldb_clk[6] += lvds_channel;
+ div_3_5_clk[2] += lvds_channel;
+ div_7_clk[2] += lvds_channel;
+ div_sel_clk[2] += lvds_channel;
+ } else {
+ ldb_clk[6] += setting->disp_id;
+ div_3_5_clk[2] += setting->disp_id;
+ div_7_clk[2] += setting->disp_id;
+ div_sel_clk[2] += setting->disp_id;
+ }
+ ldb->setting[setting_idx].ldb_di_clk = clk_get(&ldb->pdev->dev,
+ ldb_clk);
+ if (IS_ERR(ldb->setting[setting_idx].ldb_di_clk)) {
+ dev_err(&ldb->pdev->dev, "get ldb clk failed\n");
+ return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk);
+ }
+
+ ldb->setting[setting_idx].div_3_5_clk = clk_get(&ldb->pdev->dev,
+ div_3_5_clk);
+ if (IS_ERR(ldb->setting[setting_idx].div_3_5_clk)) {
+ dev_err(&ldb->pdev->dev, "get div 3.5 clk failed\n");
+ return PTR_ERR(ldb->setting[setting_idx].div_3_5_clk);
+ }
+ ldb->setting[setting_idx].div_7_clk = clk_get(&ldb->pdev->dev,
+ div_7_clk);
+ if (IS_ERR(ldb->setting[setting_idx].div_7_clk)) {
+ dev_err(&ldb->pdev->dev, "get div 7 clk failed\n");
+ return PTR_ERR(ldb->setting[setting_idx].div_7_clk);
+ }
+
+ ldb->setting[setting_idx].div_sel_clk = clk_get(&ldb->pdev->dev,
+ div_sel_clk);
+ if (IS_ERR(ldb->setting[setting_idx].div_sel_clk)) {
+ dev_err(&ldb->pdev->dev, "get div sel clk failed\n");
+ return PTR_ERR(ldb->setting[setting_idx].div_sel_clk);
+ }
+
+ di_clk[3] += setting->dev_id;
+ di_clk[7] += setting->disp_id;
+ ldb->setting[setting_idx].di_clk = clk_get(&ldb->pdev->dev,
+ di_clk);
+ if (IS_ERR(ldb->setting[setting_idx].di_clk)) {
+ dev_err(&ldb->pdev->dev, "get di clk failed\n");
+ return PTR_ERR(ldb->setting[setting_idx].di_clk);
+ }
+
+ ldb->setting[setting_idx].ch_mask = ch_mask;
+ ldb->setting[setting_idx].ch_val = ch_val;
+
+ if (is_imx6_ldb(plat_data))
+ ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb);
+
+ /* must use spec video mode defined by driver */
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp);
+ if (ret != 1)
+ fb_videomode_to_var(&setting->fbi->var, &ldb_modedb[0]);
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < ldb_modedb_sz; i++) {
+ struct fb_videomode m;
+ fb_var_to_videomode(&m, &setting->fbi->var);
+ if (fb_mode_is_equal(&m, &ldb_modedb[i])) {
+ fb_add_videomode(&ldb_modedb[i],
+ &setting->fbi->modelist);
+ break;
+ }
+ }
+
+ ldb->setting[setting_idx].ipu = setting->dev_id;
+ ldb->setting[setting_idx].di = setting->disp_id;
+
+ return ret;
+}
+
+static int ldb_post_disp_init(struct mxc_dispdrv_handle *disp,
+ int ipu_id, int disp_id)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ int setting_idx = ldb->inited ? 1 : 0;
+ int ret = 0;
+
+ if (!ldb->inited) {
+ ldb->nb.notifier_call = ldb_fb_event;
+ fb_register_client(&ldb->nb);
+ }
+
+ ret = clk_set_parent(ldb->setting[setting_idx].di_clk,
+ ldb->setting[setting_idx].ldb_di_clk);
+ if (ret) {
+ dev_err(&ldb->pdev->dev, "fail to set ldb_di clk as"
+ "the parent of ipu_di clk\n");
+ return ret;
+ }
+
+ if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1)) {
+ ret = clk_set_parent(ldb->setting[setting_idx].div_sel_clk,
+ ldb->setting[setting_idx].div_3_5_clk);
+ if (ret) {
+ dev_err(&ldb->pdev->dev, "fail to set div 3.5 clk as"
+ "the parent of div sel clk\n");
+ return ret;
+ }
+ } else {
+ ret = clk_set_parent(ldb->setting[setting_idx].div_sel_clk,
+ ldb->setting[setting_idx].div_7_clk);
+ if (ret) {
+ dev_err(&ldb->pdev->dev, "fail to set div 7 clk as"
+ "the parent of div sel clk\n");
+ return ret;
+ }
+ }
+
+ /* save active ldb setting for fb notifier */
+ ldb->setting[setting_idx].active = true;
+
+ ldb->inited = true;
+ return ret;
+}
+
+static void ldb_disp_deinit(struct mxc_dispdrv_handle *disp)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ int i;
+
+ writel(0, ldb->control_reg);
+
+ for (i = 0; i < 2; i++) {
+ clk_disable(ldb->setting[i].ldb_di_clk);
+ clk_put(ldb->setting[i].ldb_di_clk);
+ clk_put(ldb->setting[i].div_3_5_clk);
+ clk_put(ldb->setting[i].div_7_clk);
+ clk_put(ldb->setting[i].div_sel_clk);
+ }
+
+ fb_unregister_client(&ldb->nb);
+}
+
+static struct mxc_dispdrv_driver ldb_drv = {
+ .name = DISPDRV_LDB,
+ .init = ldb_disp_init,
+ .post_init = ldb_post_disp_init,
+ .deinit = ldb_disp_deinit,
+ .setup = ldb_disp_setup,
+};
+
+static int ldb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
+ uint32_t data;
+
+ if (!ldb->inited)
+ return 0;
+ data = readl(ldb->control_reg);
+ ldb->control_reg_data = data;
+ data &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
+ writel(data, ldb->control_reg);
+
+ return 0;
+}
+
+static int ldb_resume(struct platform_device *pdev)
+{
+ struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
+
+ if (!ldb->inited)
+ return 0;
+ writel(ldb->control_reg_data, ldb->control_reg);
+
+ return 0;
+}
+
+static struct platform_device_id imx_ldb_devtype[] = {
+ {
+ .name = "ldb-imx6",
+ .driver_data = LDB_IMX6,
+ }, {
+ /* sentinel */
+ }
+};
+
+static const struct of_device_id imx_ldb_dt_ids[] = {
+ { .compatible = "fsl,imx6q-ldb", .data = &imx_ldb_devtype[IMX6_LDB],},
+ { /* sentinel */ }
+};
+
+/*!
+ * This function is called by the driver framework to initialize the LDB
+ * device.
+ *
+ * @param dev The device structure for the LDB passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int ldb_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct ldb_data *ldb;
+ struct fsl_mxc_ldb_platform_data *plat_data;
+ const struct of_device_id *of_id =
+ of_match_device(imx_ldb_dt_ids, &pdev->dev);
+
+ dev_dbg(&pdev->dev, "%s enter\n", __func__);
+ ldb = devm_kzalloc(&pdev->dev, sizeof(struct ldb_data), GFP_KERNEL);
+ if (!ldb)
+ return -ENOMEM;
+
+ plat_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct fsl_mxc_ldb_platform_data),
+ GFP_KERNEL);
+ if (!plat_data)
+ return -ENOMEM;
+ pdev->dev.platform_data = plat_data;
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ plat_data->devtype = pdev->id_entry->driver_data;
+
+ ret = ldb_get_of_property(pdev, plat_data);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "get ldb of property fail\n");
+ return ret;
+ }
+
+ ldb->pdev = pdev;
+ ldb->disp_ldb = mxc_dispdrv_register(&ldb_drv);
+ mxc_dispdrv_setdata(ldb->disp_ldb, ldb);
+
+ dev_set_drvdata(&pdev->dev, ldb);
+
+ dev_dbg(&pdev->dev, "%s exit\n", __func__);
+ return ret;
+}
+
+static int ldb_remove(struct platform_device *pdev)
+{
+ struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
+
+ if (!ldb->inited)
+ return 0;
+ mxc_dispdrv_puthandle(ldb->disp_ldb);
+ mxc_dispdrv_unregister(ldb->disp_ldb);
+ return 0;
+}
+
+static struct platform_driver mxcldb_driver = {
+ .driver = {
+ .name = "mxc_ldb",
+ .of_match_table = imx_ldb_dt_ids,
+ },
+ .probe = ldb_probe,
+ .remove = ldb_remove,
+ .suspend = ldb_suspend,
+ .resume = ldb_resume,
+};
+
+static int __init ldb_init(void)
+{
+ return platform_driver_register(&mxcldb_driver);
+}
+
+static void __exit ldb_uninit(void)
+{
+ platform_driver_unregister(&mxcldb_driver);
+}
+
+module_init(ldb_init);
+module_exit(ldb_uninit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC LDB driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Copyright (C) 2011-2013 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;
+ * Necessary deferred operations can be done in mxc_dispdrv_driver->post_init(),
+ * after dev_id and disp_id pass usage check;
+ * 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;
+ *
+ * ipuv3 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 ipuv3-hw (ipu_id and disp_id).
+ *
+ * @ingroup Framebuffer
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#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);
--- /dev/null
+/*
+ * Copyright (C) 2011-2013 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 <linux/fb.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*/
+ int dev_id;
+ int disp_id;
+};
+
+struct mxc_dispdrv_driver {
+ const char *name;
+ int (*init) (struct mxc_dispdrv_handle *, struct mxc_dispdrv_setting *);
+ /* deferred operations after dev_id and disp_id pass usage check */
+ int (*post_init) (struct mxc_dispdrv_handle *, int dev_id, int disp_id);
+ void (*deinit) (struct mxc_dispdrv_handle *);
+ /* display driver enable function for extension */
+ int (*enable) (struct mxc_dispdrv_handle *);
+ /* display driver disable function, called at early part of fb_blank */
+ void (*disable) (struct mxc_dispdrv_handle *);
+ /* 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
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
-
+#define DEBUG
/*!
* @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
*/
if (ipu_ch_param_bad_alpha_pos(fbi_to_pixfmt(fbi)) &&
mxc_fbi->alpha_chan_en) {
- dev_err(fbi->device, "Bad pixel format for "
- "graphics plane fb\n");
+ dev_err(fbi->device,
+ "Bad pixel format for graphics plane fb\n");
return -EINVAL;
}
if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->setup) {
retval = mxc_fbi->dispdrv->drv->setup(mxc_fbi->dispdrv, fbi);
if (retval < 0) {
- dev_err(fbi->device, "setup error, dispdrv:%s.\n",
- mxc_fbi->dispdrv->drv->name);
+ dev_err(fbi->device, "setup error, dispdrv: %s (%d)\n",
+ mxc_fbi->dispdrv->drv->name, retval);
return -EINVAL;
}
}
if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->enable) {
retval = mxc_fbi->dispdrv->drv->enable(mxc_fbi->dispdrv);
if (retval < 0) {
- dev_err(fbi->device, "enable error, dispdrv:%s.\n",
- mxc_fbi->dispdrv->drv->name);
+ dev_err(fbi->device, "enable error, dispdrv: %s (%d)\n",
+ mxc_fbi->dispdrv->drv->name, retval);
return -EINVAL;
}
}
ret = mxcfb_get_of_property(pdev, plat_data);
if (ret < 0) {
- dev_err(&pdev->dev, "get mxcfb of property fail\n");
+ dev_err(&pdev->dev, "get mxcfb of property failed: %d\n", ret);
return ret;
}
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative)
-#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE)
-extern struct cpufreq_governor cpufreq_gov_interactive;
-#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_interactive)
#endif
/*********************************************************************
+++ /dev/null
-/*
- * Copyright (C) 2011-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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __ISL29023_H__
-#define __ISL29023_H__
-
-#include <linux/types.h>
-
-#define ISL29023_PD_MODE 0x0
-#define ISL29023_ALS_ONCE_MODE 0x1
-#define ISL29023_IR_ONCE_MODE 0x2
-#define ISL29023_ALS_CONT_MODE 0x5
-#define ISL29023_IR_CONT_MODE 0x6
-
-#define ISL29023_INT_PERSISTS_1 0x0
-#define ISL29023_INT_PERSISTS_4 0x1
-#define ISL29023_INT_PERSISTS_8 0x2
-#define ISL29023_INT_PERSISTS_16 0x3
-
-#define ISL29023_RES_16 0x0
-#define ISL29023_RES_12 0x1
-#define ISL29023_RES_8 0x2
-#define ISL29023_RES_4 0x3
-
-#define ISL29023_RANGE_1K 0x0
-#define ISL29023_RANGE_4K 0x1
-#define ISL29023_RANGE_16K 0x2
-#define ISL29023_RANGE_64K 0x3
-
-#endif
unsigned int data_sector_size; /* 512 bytes or 4KB */
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
- unsigned int boot_size;
bool boot_ro_lockable;
u8 raw_exception_status; /* 54 */
u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */
- u8 boot_bus_width; /* 177 */
- u8 boot_config; /* 179 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
u8 raw_hc_erase_gap_size; /* 221 */
u8 raw_erase_timeout_mult; /* 223 */
u8 raw_hc_erase_grp_size; /* 224 */
- u8 boot_info; /* 228 */
u8 raw_sec_trim_mult; /* 229 */
u8 raw_sec_erase_mult; /* 230 */
u8 raw_sec_feature_support;/* 231 */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
-#define EXT_CSD_BOOT_BUS_WIDTH 177 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
-#define EXT_CSD_BOOT_INFO 228 /* RO, 1 bytes */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
-#define EXT_CSD_BOOT_BUS_WIDTH_MASK (0x1F)
-#define EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK (0x3 << 3)
-#define EXT_CSD_BOOT_BUS_WIDTH_MODE_SDR_NORMAL (0x0)
-#define EXT_CSD_BOOT_BUS_WIDTH_MODE_SDR_HIGH (0x1)
-#define EXT_CSD_BOOT_BUS_WIDTH_MODE_DDR (0x2)
-#define EXT_CSD_BOOT_BUS_WIDTH_RST_WIDTH (1 << 2)
-#define EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK (0x3)
-#define EXT_CSD_BOOT_BUS_WIDTH_1_SDR_4_DDR (0x0)
-#define EXT_CSD_BOOT_BUS_WIDTH_4_SDR_4_DDR (0x1)
-#define EXT_CSD_BOOT_BUS_WIDTH_8_SDR_8_DDR (0x2)
-
-#define EXT_CSD_BOOT_ACK_ENABLE (0x1 << 6)
-#define EXT_CSD_BOOT_PARTITION_ENABLE_MASK (0x7 << 3)
-#define EXT_CSD_BOOT_PARTITION_DISABLE (0x0)
-#define EXT_CSD_BOOT_PARTITION_PART1 (0x1 << 3)
-#define EXT_CSD_BOOT_PARTITION_PART2 (0x2 << 3)
-#define EXT_CSD_BOOT_PARTITION_USER (0x7 << 3)
-
-#define EXT_CSD_BOOT_PARTITION_ACCESS_MASK (0x7)
-#define EXT_CSD_BOOT_PARTITION_ACCESS_DISABLE (0x0)
-#define EXT_CSD_BOOT_PARTITION_ACCESS_PART1 (0x1)
-#define EXT_CSD_BOOT_PARTITION_ACCESS_PART2 (0x2)
-
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
if (map->cached)
memcpy(to, (char *)map->cached + from, len);
else
- memcpy(to, map->virt + from, len);
+ memcpy_fromio(to, map->virt + from, len);
}
static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
struct vpu_mem_desc {
u32 size;
dma_addr_t phy_addr;
- u32 cpu_addr; /* cpu address to free the dma mem */
- u32 virt_uaddr; /* virtual user space address */
+ void *cpu_addr; /* cpu address to free the dma mem */
+ void *virt_uaddr; /* virtual user space address */
};
#define VPU_IOC_MAGIC 'V'
--- /dev/null
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*
+ * @file linux/mxcfb.h
+ *
+ * @brief Global header file for the MXC Frame buffer
+ *
+ * @ingroup Framebuffer
+ */
+#ifndef __LINUX_MXCFB_H__
+#define __LINUX_MXCFB_H__
+
+#include <uapi/linux/mxcfb.h>
+
+extern struct fb_videomode mxcfb_modedb[];
+extern int mxcfb_modedb_sz;
+
+enum {
+ MXC_DISP_SPEC_DEV = 0,
+ MXC_DISP_DDC_DEV = 1,
+};
+
+enum {
+ MXCFB_REFRESH_OFF,
+ MXCFB_REFRESH_AUTO,
+ MXCFB_REFRESH_PARTIAL,
+};
+
+int mxcfb_set_refresh_mode(struct fb_info *fbi, int mode,
+ struct mxcfb_rect *update_region);
+int mxc_elcdif_frame_addr_setup(dma_addr_t phys);
+void mxcfb_elcdif_register_mode(const struct fb_videomode *modedb,
+ int num_modes, int dev_mode);
+
+#endif
+++ /dev/null
-/*
- * Copyright (C) 2013 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 __IMXUSB6_CHARGER_H
-#define __IMXUSB6_CHARGER_H
-
-#include <linux/power_supply.h>
-enum battery_charging_spec {
- BATTERY_CHARGING_SPEC_NONE = 0,
- BATTERY_CHARGING_SPEC_UNKNOWN,
- BATTERY_CHARGING_SPEC_1_0,
- BATTERY_CHARGING_SPEC_1_1,
- BATTERY_CHARGING_SPEC_1_2,
-};
-
-struct usb_charger {
- /* The anatop regmap */
- struct regmap *anatop;
- /* USB controller */
- struct device *dev;
- struct power_supply psy;
- struct mutex lock;
-
- /* Compliant with Battery Charging Specification version (if any) */
- enum battery_charging_spec bc;
-
- /* properties */
- unsigned present:1;
- unsigned online:1;
- unsigned max_current;
- int (*connect)(struct usb_charger *charger);
- int (*disconnect)(struct usb_charger *charger);
- int (*set_power)(struct usb_charger *charger, unsigned mA);
-
- int (*detect)(struct usb_charger *charger);
-};
-
-#ifdef CONFIG_IMX6_USB_CHARGER
-extern void imx6_usb_remove_charger(struct usb_charger *charger);
-extern int imx6_usb_create_charger(struct usb_charger *charger,
- const char *name);
-extern int imx6_usb_vbus_disconnect(struct usb_charger *charger);
-extern int imx6_usb_vbus_connect(struct usb_charger *charger);
-extern int imx6_usb_charger_detect_post(struct usb_charger *charger);
-#else
-void imx6_usb_remove_charger(struct usb_charger *charger)
-{
-
-}
-
-int imx6_usb_create_charger(struct usb_charger *charger,
- const char *name)
-{
- return -ENODEV;
-}
-
-int imx6_usb_vbus_disconnect(struct usb_charger *charger)
-{
- return -ENODEV;
-}
-
-int imx6_usb_vbus_connect(struct usb_charger *charger)
-{
- return -ENODEV;
-}
-int imx6_usb_charger_detect_post(struct usb_charger *charger)
-{
- return -ENODEV;
-}
-#endif
-
-#endif /* __IMXUSB6_CHARGER_H */
+++ /dev/null
-/*
- * sabresd_battery.h - Maxim 8903 USB/Adapter Charger Driver
- *
- * Copyright (C) 2011 Samsung Electronics
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
- * Based on max8903_charger.h
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#ifndef __MAX8903_SABRESD_H__
-#define __MAX8903_SABRESD_H__
-
-struct max8903_pdata {
- /*
- * GPIOs
- * cen, chg, flt, and usus are optional.
- * dok, dcm, and uok are not optional depending on the status of
- * dc_valid and usb_valid.
- */
- int cen; /* Charger Enable input */
- int dok; /* DC(Adapter) Power OK output */
- int uok; /* USB Power OK output */
- int chg; /* Charger status output */
- int flt; /* Fault output */
- int dcm; /* Current-Limit Mode input (1: DC, 2: USB) */
- int usus; /* USB Suspend Input (1: suspended) */
- int feature_flag;/* battery capacity feature(0:enable, 1:disable) */
-
- /*
- * DCM wired to Logic High Set this true when DCM pin connect to
- * Logic high.
- */
- bool dcm_always_high;
-
- /*
- * DC(Adapter/TA) is wired
- * When dc_valid is true,
- * dok and dcm should be valid.
- *
- * At least one of dc_valid or usb_valid should be true.
- */
- bool dc_valid;
- /*
- * USB is wired
- * When usb_valid is true,
- * uok should be valid.
- */
- bool usb_valid;
-};
-
-#endif /* __SABRESD_BATTERY_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2011-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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __UAPI_LINUX_ISL29023_H__
-#define __UAPI_LINUX_ISL29023_H__
-
-#include <linux/types.h>
-
-#define ISL29023_PD_MODE 0x0
-#define ISL29023_ALS_ONCE_MODE 0x1
-#define ISL29023_IR_ONCE_MODE 0x2
-#define ISL29023_ALS_CONT_MODE 0x5
-#define ISL29023_IR_CONT_MODE 0x6
-
-#define ISL29023_INT_PERSISTS_1 0x0
-#define ISL29023_INT_PERSISTS_4 0x1
-#define ISL29023_INT_PERSISTS_8 0x2
-#define ISL29023_INT_PERSISTS_16 0x3
-
-#define ISL29023_RES_16 0x0
-#define ISL29023_RES_12 0x1
-#define ISL29023_RES_8 0x2
-#define ISL29023_RES_4 0x3
-
-#define ISL29023_RANGE_1K 0x0
-#define ISL29023_RANGE_4K 0x1
-#define ISL29023_RANGE_16K 0x2
-#define ISL29023_RANGE_64K 0x3
-
-#endif
--- /dev/null
+/*
+ * Copyright (C) 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * @file uapi/linux/mxcfb.h
+ *
+ * @brief Global header file for the MXC frame buffer
+ *
+ * @ingroup Framebuffer
+ */
+#ifndef __ASM_ARCH_MXCFB_H__
+#define __ASM_ARCH_MXCFB_H__
+
+#include <linux/fb.h>
+
+#define FB_SYNC_OE_LOW_ACT 0x80000000
+#define FB_SYNC_CLK_LAT_FALL 0x40000000
+#define FB_SYNC_DATA_INVERT 0x20000000
+#define FB_SYNC_CLK_IDLE_EN 0x10000000
+#define FB_SYNC_SHARP_MODE 0x08000000
+#define FB_SYNC_SWAP_RGB 0x04000000
+#define FB_ACCEL_TRIPLE_FLAG 0x00000000
+#define FB_ACCEL_DOUBLE_FLAG 0x00000001
+
+struct mxcfb_gbl_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mxcfb_loc_alpha {
+ int enable;
+ int alpha_in_pixel;
+ unsigned long alpha_phy_addr0;
+ unsigned long alpha_phy_addr1;
+};
+
+struct mxcfb_color_key {
+ int enable;
+ __u32 color_key;
+};
+
+struct mxcfb_pos {
+ __u16 x;
+ __u16 y;
+};
+
+struct mxcfb_gamma {
+ int enable;
+ int constk[16];
+ int slopek[16];
+};
+
+struct mxcfb_rect {
+ __u32 top;
+ __u32 left;
+ __u32 width;
+ __u32 height;
+};
+
+#define GRAYSCALE_8BIT 0x1
+#define GRAYSCALE_8BIT_INVERTED 0x2
+#define GRAYSCALE_4BIT 0x3
+#define GRAYSCALE_4BIT_INVERTED 0x4
+
+#define AUTO_UPDATE_MODE_REGION_MODE 0
+#define AUTO_UPDATE_MODE_AUTOMATIC_MODE 1
+
+#define UPDATE_SCHEME_SNAPSHOT 0
+#define UPDATE_SCHEME_QUEUE 1
+#define UPDATE_SCHEME_QUEUE_AND_MERGE 2
+
+#define UPDATE_MODE_PARTIAL 0x0
+#define UPDATE_MODE_FULL 0x1
+
+#define WAVEFORM_MODE_AUTO 257
+
+#define TEMP_USE_AMBIENT 0x1000
+
+#define EPDC_FLAG_ENABLE_INVERSION 0x01
+#define EPDC_FLAG_FORCE_MONOCHROME 0x02
+#define EPDC_FLAG_USE_CMAP 0x04
+#define EPDC_FLAG_USE_ALT_BUFFER 0x100
+#define EPDC_FLAG_TEST_COLLISION 0x200
+#define EPDC_FLAG_GROUP_UPDATE 0x400
+#define EPDC_FLAG_USE_DITHERING_Y1 0x2000
+#define EPDC_FLAG_USE_DITHERING_Y4 0x4000
+
+#define FB_POWERDOWN_DISABLE -1
+
+struct mxcfb_alt_buffer_data {
+ __u32 phys_addr;
+ __u32 width; /* width of entire buffer */
+ __u32 height; /* height of entire buffer */
+ struct mxcfb_rect alt_update_region; /* region within buffer to update */
+};
+
+struct mxcfb_update_data {
+ struct mxcfb_rect update_region;
+ __u32 waveform_mode;
+ __u32 update_mode;
+ __u32 update_marker;
+ int temp;
+ unsigned int flags;
+ struct mxcfb_alt_buffer_data alt_buffer_data;
+};
+
+struct mxcfb_update_marker_data {
+ __u32 update_marker;
+ __u32 collision_test;
+};
+
+/*
+ * Structure used to define waveform modes for driver
+ * Needed for driver to perform auto-waveform selection
+ */
+struct mxcfb_waveform_modes {
+ int mode_init;
+ int mode_du;
+ int mode_gc4;
+ int mode_gc8;
+ int mode_gc16;
+ int mode_gc32;
+};
+
+/*
+ * Structure used to define a 5*3 matrix of parameters for
+ * setting IPU DP CSC module related to this framebuffer.
+ */
+struct mxcfb_csc_matrix {
+ int param[5][3];
+};
+
+#define MXCFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
+#define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha)
+#define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key)
+#define MXCFB_SET_OVERLAY_POS _IOWR('F', 0x24, struct mxcfb_pos)
+#define MXCFB_GET_FB_IPU_CHAN _IOR('F', 0x25, u_int32_t)
+#define MXCFB_SET_LOC_ALPHA _IOWR('F', 0x26, struct mxcfb_loc_alpha)
+#define MXCFB_SET_LOC_ALP_BUF _IOW('F', 0x27, unsigned long)
+#define MXCFB_SET_GAMMA _IOW('F', 0x28, struct mxcfb_gamma)
+#define MXCFB_GET_FB_IPU_DI _IOR('F', 0x29, u_int32_t)
+#define MXCFB_GET_DIFMT _IOR('F', 0x2A, u_int32_t)
+#define MXCFB_GET_FB_BLANK _IOR('F', 0x2B, u_int32_t)
+#define MXCFB_SET_DIFMT _IOW('F', 0x2C, u_int32_t)
+#define MXCFB_CSC_UPDATE _IOW('F', 0x2D, struct mxcfb_csc_matrix)
+
+/* IOCTLs for E-ink panel updates */
+#define MXCFB_SET_WAVEFORM_MODES _IOW('F', 0x2B, struct mxcfb_waveform_modes)
+#define MXCFB_SET_TEMPERATURE _IOW('F', 0x2C, int32_t)
+#define MXCFB_SET_AUTO_UPDATE_MODE _IOW('F', 0x2D, __u32)
+#define MXCFB_SEND_UPDATE _IOW('F', 0x2E, struct mxcfb_update_data)
+#define MXCFB_WAIT_FOR_UPDATE_COMPLETE _IOWR('F', 0x2F, struct mxcfb_update_marker_data)
+#define MXCFB_SET_PWRDOWN_DELAY _IOW('F', 0x30, int32_t)
+#define MXCFB_GET_PWRDOWN_DELAY _IOR('F', 0x31, int32_t)
+#define MXCFB_SET_UPDATE_SCHEME _IOW('F', 0x32, __u32)
+#define MXCFB_GET_WORK_BUFFER _IOWR('F', 0x34, unsigned long)
+#endif
Enable I2S based access to the TLV320AIC23B codec attached
to the SSI interface
-config SND_SOC_IMX_CS42888
- tristate "SoC Audio support for i.MX boards with cs42888"
- depends on OF && I2C
- select SND_SOC_CS42888
- select SND_SOC_IMX_PCM_DMA
- select SND_SOC_FSL_ESAI
- select SND_SOC_FSL_UTILS
- help
- SoC Audio support for i.MX boards with cs42888
- Say Y if you want to add support for SoC audio on an i.MX board with
- a cs42888 codec.
-
config SND_SOC_IMX_WM8962
tristate "SoC Audio support for i.MX boards with wm8962"
depends on OF && I2C && INPUT
select SND_SOC_MC13783
select SND_SOC_IMX_PCM_DMA
-config SND_SOC_IMX_HDMI
- tristate "SoC Audio support for i.MX boards with HDMI port"
- depends on MFD_MXC_HDMI
- select SND_SOC_IMX_HDMI_DMA
- select SND_SOC_FSL_HDMI
- select SND_SOC_OMAP_HDMI_CODEC
- help
- SoC Audio support for i.MX boards with HDMI audio
- Say Y if you want to add support for SoC audio on an i.MX board with
- IMX HDMI.
-
-config SND_SOC_IMX_SI476X
- tristate "SoC Audio support for i.MX boards with si476x"
- select SND_SOC_IMX_PCM_DMA
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_FSL_SSI
- select SND_SOC_FSL_UTILS
- select SND_SOC_SI476X
- help
- SoC Audio support for i.MX boards with SI476x
- Say Y if you want to add support for Soc audio for the AMFM Tuner chip
- SI476x module.
-
endif # SND_IMX_SOC
endmenu
snd-soc-phycore-ac97-objs := phycore-ac97.o
snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
-snd-soc-imx-cs42888-objs := imx-cs42888.o
snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
snd-soc-imx-wm8962-objs := imx-wm8962.o
snd-soc-imx-spdif-objs := imx-spdif.o
snd-soc-imx-mc13783-objs := imx-mc13783.o
-snd-soc-imx-hdmi-objs := imx-hdmi.o
-snd-soc-imx-si476x-objs := imx-si476x.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
-obj-$(CONFIG_SND_SOC_IMX_CS42888) += snd-soc-imx-cs42888.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
-obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
-obj-$(CONFIG_SND_SOC_IMX_SI476X) += snd-soc-imx-si476x.o
+++ /dev/null
-/*
- * Copyright (C) 2010-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
- */
-
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_i2c.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
-#include <sound/pcm_params.h>
-
-#include "fsl_esai.h"
-#include "fsl_asrc.h"
-
-#define CODEC_CLK_EXTER_OSC 1
-#define CODEC_CLK_ESAI_HCKT 2
-
-struct imx_priv {
- int hw;
- int fe_output_rate;
- int fe_output_width;
- unsigned int mclk_freq;
- unsigned int codec_mclk;
- struct platform_device *pdev;
-};
-
-static struct imx_priv card_priv;
-
-static int imx_cs42888_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct imx_priv *priv = &card_priv;
-
- if (!cpu_dai->active)
- priv->hw = 0;
- return 0;
-}
-
-static void imx_cs42888_shutdown(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct imx_priv *priv = &card_priv;
-
- if (!cpu_dai->active)
- priv->hw = 0;
-}
-
-static const struct {
- int rate;
- int ratio1;
- int ratio2;
-} sr_vals[] = {
- { 32000, 5, 3 },
- { 48000, 5, 3 },
- { 64000, 2, 1 },
- { 96000, 2, 1 },
- { 128000, 2, 1 },
- { 44100, 5, 3 },
- { 88200, 2, 1 },
- { 176400, 0, 0 },
- { 192000, 0, 0 },
-};
-
-static int imx_cs42888_surround_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct imx_priv *priv = &card_priv;
- unsigned int rate = params_rate(params);
- unsigned int lrclk_ratio = 0, i;
- u32 dai_format = 0;
-
- if (priv->hw)
- return 0;
-
- priv->hw = 1;
-
- if (priv->codec_mclk & CODEC_CLK_ESAI_HCKT) {
- for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
- if (sr_vals[i].rate == rate) {
- lrclk_ratio = sr_vals[i].ratio1;
- break;
- }
- }
- if (i == ARRAY_SIZE(sr_vals)) {
- dev_err(&priv->pdev->dev, "Unsupported rate %dHz\n", rate);
- return -EINVAL;
- }
-
- dai_format = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
-
- /* set the ESAI system clock as output */
- snd_soc_dai_set_sysclk(cpu_dai, ESAI_CLK_EXTAL_DIV,
- priv->mclk_freq, SND_SOC_CLOCK_OUT);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PM, 2);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PM, 2);
- /* set codec Master clock */
- snd_soc_dai_set_sysclk(codec_dai, 0, priv->mclk_freq,\
- SND_SOC_CLOCK_IN);
- } else if (priv->codec_mclk & CODEC_CLK_EXTER_OSC) {
- for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
- if (sr_vals[i].rate == rate) {
- lrclk_ratio = sr_vals[i].ratio2;
- break;
- }
- }
- if (i == ARRAY_SIZE(sr_vals)) {
- dev_err(&priv->pdev->dev, "Unsupported rate %dHz\n", rate);
- return -EINVAL;
- }
-
- dai_format = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
-
- snd_soc_dai_set_sysclk(cpu_dai, ESAI_CLK_EXTAL,
- priv->mclk_freq, SND_SOC_CLOCK_OUT);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PM, 0);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PM, 0);
- snd_soc_dai_set_sysclk(codec_dai, 0, priv->mclk_freq,\
- SND_SOC_CLOCK_IN);
- }
-
- /* set cpu DAI configuration */
- snd_soc_dai_set_fmt(cpu_dai, dai_format);
- /* set i.MX active slot mask */
- snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
- /* set the ratio */
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PSR, 1);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_FP, lrclk_ratio);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PSR, 1);
- snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_FP, lrclk_ratio);
-
- /* set codec DAI configuration */
- snd_soc_dai_set_fmt(codec_dai, dai_format);
- return 0;
-}
-
-static struct snd_soc_ops imx_cs42888_surround_ops = {
- .startup = imx_cs42888_startup,
- .shutdown = imx_cs42888_shutdown,
- .hw_params = imx_cs42888_surround_hw_params,
-};
-
-static const struct snd_soc_dapm_widget imx_cs42888_dapm_widgets[] = {
- SND_SOC_DAPM_LINE("Line Out Jack", NULL),
- SND_SOC_DAPM_LINE("Line In Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
- /* Line out jack */
- {"Line Out Jack", NULL, "AOUT1L"},
- {"Line Out Jack", NULL, "AOUT1R"},
- {"Line Out Jack", NULL, "AOUT2L"},
- {"Line Out Jack", NULL, "AOUT2R"},
- {"Line Out Jack", NULL, "AOUT3L"},
- {"Line Out Jack", NULL, "AOUT3R"},
- {"Line Out Jack", NULL, "AOUT4L"},
- {"Line Out Jack", NULL, "AOUT4R"},
- {"AIN1L", NULL, "Line In Jack"},
- {"AIN1R", NULL, "Line In Jack"},
- {"AIN2L", NULL, "Line In Jack"},
- {"AIN2R", NULL, "Line In Jack"},
- {"esai-Playback", NULL, "asrc-Playback"},
- {"codec-Playback", NULL, "esai-Playback"},/*Playback is the codec dai*/
-};
-
-static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params) {
-
- struct imx_priv *priv = &card_priv;
-
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = priv->fe_output_rate;
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = priv->fe_output_rate;
- snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT));
- if (priv->fe_output_width == 16)
- snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- SNDRV_PCM_FORMAT_S16_LE);
- else
- snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- SNDRV_PCM_FORMAT_S24_LE);
- return 0;
-}
-
-static struct snd_soc_dai_link imx_cs42888_dai[] = {
- {
- .name = "HiFi",
- .stream_name = "HiFi",
- .codec_dai_name = "CS42888",
- .ops = &imx_cs42888_surround_ops,
- },
- {
- .name = "HiFi-ASRC-FE",
- .stream_name = "HiFi-ASRC-FE",
- .codec_name = "snd-soc-dummy",
- .codec_dai_name = "snd-soc-dummy-dai",
- .dynamic = 1,
- },
- {
- .name = "HiFi-ASRC-BE",
- .stream_name = "HiFi-ASRC-BE",
- .codec_dai_name = "CS42888",
- .platform_name = "snd-soc-dummy",
- .no_pcm = 1,
- .ops = &imx_cs42888_surround_ops,
- .be_hw_params_fixup = be_hw_params_fixup,
- },
-};
-
-static struct snd_soc_card snd_soc_card_imx_cs42888 = {
- .name = "cs42888-audio",
- .dai_link = imx_cs42888_dai,
- .dapm_widgets = imx_cs42888_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(imx_cs42888_dapm_widgets),
- .dapm_routes = audio_map,
- .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-/*
- * This function will register the snd_soc_pcm_link drivers.
- */
-static int imx_cs42888_probe(struct platform_device *pdev)
-{
- struct device_node *esai_np, *codec_np;
- struct device_node *asrc_np;
- struct platform_device *esai_pdev;
- struct platform_device *asrc_pdev = NULL;
- struct i2c_client *codec_dev;
- struct imx_priv *priv = &card_priv;
- struct clk *codec_clk = NULL;
- const char *mclk_name;
- int ret;
-
- priv->pdev = pdev;
-
- esai_np = of_parse_phandle(pdev->dev.of_node, "esai-controller", 0);
- codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
- if (!esai_np || !codec_np) {
- dev_err(&pdev->dev, "phandle missing or invalid\n");
- ret = -EINVAL;
- goto fail;
- }
-
- asrc_np = of_parse_phandle(pdev->dev.of_node, "asrc-controller", 0);
- if (asrc_np) {
- asrc_pdev = of_find_device_by_node(asrc_np);
- if (asrc_pdev) {
- struct fsl_asrc_p2p *asrc_p2p;
- asrc_p2p = platform_get_drvdata(asrc_pdev);
- asrc_p2p->per_dev = ESAI;
- priv->fe_output_rate = asrc_p2p->output_rate;
- priv->fe_output_width = asrc_p2p->output_width;
- }
- }
-
- esai_pdev = of_find_device_by_node(esai_np);
- if (!esai_pdev) {
- dev_err(&pdev->dev, "failed to find ESAI platform device\n");
- ret = -EINVAL;
- goto fail;
- }
- codec_dev = of_find_i2c_device_by_node(codec_np);
- if (!codec_dev) {
- dev_err(&pdev->dev, "failed to find codec platform device\n");
- ret = -EINVAL;
- goto fail;
- }
-
- /*if there is no asrc controller, we only enable one device*/
- if (!asrc_pdev) {
- imx_cs42888_dai[0].codec_of_node = codec_np;
- imx_cs42888_dai[0].cpu_dai_name = dev_name(&esai_pdev->dev);
- imx_cs42888_dai[0].platform_of_node = esai_np;
- snd_soc_card_imx_cs42888.num_links = 1;
- } else {
- imx_cs42888_dai[0].codec_of_node = codec_np;
- imx_cs42888_dai[0].cpu_dai_name = dev_name(&esai_pdev->dev);
- imx_cs42888_dai[0].platform_of_node = esai_np;
- imx_cs42888_dai[1].cpu_dai_name = dev_name(&asrc_pdev->dev);
- imx_cs42888_dai[1].platform_name = "imx-pcm-asrc";
- imx_cs42888_dai[2].codec_of_node = codec_np;
- imx_cs42888_dai[2].cpu_dai_name = dev_name(&esai_pdev->dev);
- snd_soc_card_imx_cs42888.num_links = 3;
- }
-
- codec_clk = devm_clk_get(&codec_dev->dev, NULL);
- if (IS_ERR(codec_clk)) {
- ret = PTR_ERR(codec_clk);
- dev_err(&codec_dev->dev, "failed to get codec clk: %d\n", ret);
- goto fail;
- }
- priv->mclk_freq = clk_get_rate(codec_clk);
-
- ret = of_property_read_string(codec_np, "clock-names", &mclk_name);
- if (ret) {
- dev_err(&pdev->dev, "%s: failed to get mclk source\n", __func__);
- goto fail;
- }
- if (!strcmp(mclk_name, "codec_osc"))
- priv->codec_mclk = CODEC_CLK_EXTER_OSC;
- else if (!strcmp(mclk_name, "esai"))
- priv->codec_mclk = CODEC_CLK_ESAI_HCKT;
- else {
- dev_err(&pdev->dev, "mclk source is not correct %s\n", mclk_name);
- goto fail;
- }
-
- snd_soc_card_imx_cs42888.dev = &pdev->dev;
-
- ret = snd_soc_register_card(&snd_soc_card_imx_cs42888);
- if (ret)
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-fail:
- if (esai_np)
- of_node_put(esai_np);
- if (codec_np)
- of_node_put(codec_np);
- return ret;
-}
-
-static int imx_cs42888_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_card(&snd_soc_card_imx_cs42888);
- return 0;
-}
-
-static const struct of_device_id imx_cs42888_dt_ids[] = {
- { .compatible = "fsl,imx-audio-cs42888", },
- { /* sentinel */ }
-};
-
-static struct platform_driver imx_cs42888_driver = {
- .probe = imx_cs42888_probe,
- .remove = imx_cs42888_remove,
- .driver = {
- .name = "imx-cs42888",
- .owner = THIS_MODULE,
- .of_match_table = imx_cs42888_dt_ids,
- },
-};
-module_platform_driver(imx_cs42888_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("ALSA SoC cs42888 Machine Layer Driver");
-MODULE_ALIAS("platform:imx-cs42888");
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * ASoC HDMI Transmitter driver for IMX development boards
- *
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
- *
- * based on stmp3780_devb_hdmi.c
- *
- * Vladimir Barinov <vbarinov@embeddedalley.com>
- *
- * Copyright 2008 SigmaTel, Inc
- * Copyright 2008 Embedded Alley Solutions, Inc
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/mfd/mxc-hdmi-core.h>
-#include <sound/soc.h>
-
-#include "imx-hdmi.h"
-
-/* imx digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link imx_hdmi_dai_link = {
- .name = "i.MX HDMI Audio Tx",
- .stream_name = "i.MX HDMI Audio Tx",
- .codec_dai_name = "hdmi-hifi",
- .codec_name = "hdmi-audio-codec",
- .platform_name = "imx-hdmi-audio",
-};
-
-static struct snd_soc_card snd_soc_card_imx_hdmi = {
- .name = "imx-hdmi-soc",
- .dai_link = &imx_hdmi_dai_link,
- .num_links = 1,
-};
-
-static struct platform_device *codec_dev;
-
-static int imx_hdmi_audio_probe(struct platform_device *pdev)
-{
- struct device_node *hdmi_np, *np = pdev->dev.of_node;
- struct snd_soc_card *card = &snd_soc_card_imx_hdmi;
- struct platform_device *hdmi_pdev;
- int ret = 0;
-
- if (!hdmi_get_registered()) {
- dev_err(&pdev->dev, "initialize HDMI-audio failed. load HDMI-video first!\n");
- return -ENODEV;
- }
-
- hdmi_np = of_parse_phandle(np, "hdmi-controller", 0);
- if (!hdmi_np) {
- dev_err(&pdev->dev, "failed to find hdmi-audio cpudai\n");
- ret = -EINVAL;
- goto end;
- }
-
- hdmi_pdev = of_find_device_by_node(hdmi_np);
- if (!hdmi_pdev) {
- dev_err(&pdev->dev, "failed to find SSI platform device\n");
- ret = -EINVAL;
- goto end;
- }
-
- codec_dev = platform_device_register_simple("hdmi-audio-codec", -1, NULL, 0);
- if (IS_ERR(codec_dev)) {
- dev_err(&pdev->dev, "failed to register HDMI audio codec\n");
- ret = PTR_ERR(codec_dev);
- goto end;
- }
-
- card->dev = &pdev->dev;
- card->dai_link->cpu_dai_name = dev_name(&hdmi_pdev->dev);
-
- ret = snd_soc_register_card(card);
- if (ret) {
- dev_err(&pdev->dev, "failed to register card: %d\n", ret);
- goto err_card;
- }
-
- goto end;
-
-err_card:
- platform_device_unregister(codec_dev);
-end:
- if (hdmi_np)
- of_node_put(hdmi_np);
-
- return ret;
-}
-
-static int imx_hdmi_audio_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &snd_soc_card_imx_hdmi;
-
- platform_device_unregister(codec_dev);
- snd_soc_unregister_card(card);
-
- return 0;
-}
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
- { .compatible = "fsl,imx-audio-hdmi", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
-static struct platform_driver imx_hdmi_audio_driver = {
- .probe = imx_hdmi_audio_probe,
- .remove = imx_hdmi_audio_remove,
- .driver = {
- .of_match_table = imx_hdmi_dt_ids,
- .name = "imx-audio-hdmi",
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(imx_hdmi_audio_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("IMX HDMI TX ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-audio-hdmi");
+++ /dev/null
-/*
- * Copyright (C) 2008-2013 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
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <sound/soc.h>
-
-#include "imx-audmux.h"
-
-static int imx_audmux_config(int slave, int master)
-{
- unsigned int ptcr, pdcr;
- slave = slave - 1;
- master = master - 1;
-
- ptcr = IMX_AUDMUX_V2_PTCR_SYN |
- IMX_AUDMUX_V2_PTCR_TFSDIR |
- IMX_AUDMUX_V2_PTCR_TFSEL(slave) |
- IMX_AUDMUX_V2_PTCR_TCLKDIR |
- IMX_AUDMUX_V2_PTCR_TCSEL(slave);
- pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(slave);
- imx_audmux_v2_configure_port(master, ptcr, pdcr);
-
- ptcr = IMX_AUDMUX_V2_PTCR_SYN;
- pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(master);
- imx_audmux_v2_configure_port(slave, ptcr, pdcr);
-
- return 0;
-}
-
-static int imx_si476x_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- u32 channels = params_channels(params);
- u32 rate = params_rate(params);
- u32 bclk = rate * channels * 32;
- int ret = 0;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret) {
- dev_err(cpu_dai->dev, "failed to set dai fmt\n");
- return ret;
- }
-
- ret = snd_soc_dai_set_tdm_slot(cpu_dai,
- channels == 1 ? 0xfffffffe : 0xfffffffc,
- channels == 1 ? 0xfffffffe : 0xfffffffc,
- 2, 32);
- if (ret) {
- dev_err(cpu_dai->dev, "failed to set dai tdm slot\n");
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, 0, bclk, SND_SOC_CLOCK_OUT);
- if (ret)
- dev_err(cpu_dai->dev, "failed to set sysclk\n");
-
- return ret;
-}
-
-static struct snd_soc_ops imx_si476x_ops = {
- .hw_params = imx_si476x_hw_params,
-};
-
-static struct snd_soc_dai_link imx_dai = {
- .name = "imx-si476x",
- .stream_name = "imx-si476x",
- .codec_dai_name = "si476x-codec",
- .codec_name = "si476x-codec.99",
- .ops = &imx_si476x_ops,
-};
-
-static struct snd_soc_card snd_soc_card_imx_3stack = {
- .name = "imx-audio-si476x",
- .dai_link = &imx_dai,
- .num_links = 1,
-};
-
-static int imx_si476x_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &snd_soc_card_imx_3stack;
- struct device_node *ssi_np, *np = pdev->dev.of_node;
- struct platform_device *ssi_pdev;
- int int_port, ext_port, ret;
-
- ret = of_property_read_u32(np, "mux-int-port", &int_port);
- if (ret) {
- dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
- return ret;
- }
-
- ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
- if (ret) {
- dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
- return ret;
- }
-
- imx_audmux_config(int_port, ext_port);
-
- ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
- if (!ssi_np) {
- dev_err(&pdev->dev, "phandle missing or invalid\n");
- return -EINVAL;
- }
-
- ssi_pdev = of_find_device_by_node(ssi_np);
- if (!ssi_pdev) {
- dev_err(&pdev->dev, "failed to find SSI platform device\n");
- ret = -EINVAL;
- goto end;
- }
-
- card->dev = &pdev->dev;
- card->dai_link->cpu_dai_name = dev_name(&ssi_pdev->dev);
- card->dai_link->platform_of_node = ssi_np;
-
- ret = snd_soc_register_card(card);
- if (ret)
- dev_err(&pdev->dev, "Failed to register card: %d\n", ret);
-
-end:
- if (ssi_np)
- of_node_put(ssi_np);
-
- return ret;
-}
-
-static int imx_si476x_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &snd_soc_card_imx_3stack;
-
- snd_soc_unregister_card(card);
-
- return 0;
-}
-
-static const struct of_device_id imx_si476x_dt_ids[] = {
- { .compatible = "fsl,imx-audio-si476x", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_si476x_dt_ids);
-
-static struct platform_driver imx_si476x_driver = {
- .driver = {
- .name = "imx-tuner-si476x",
- .owner = THIS_MODULE,
- .of_match_table = imx_si476x_dt_ids,
- },
- .probe = imx_si476x_probe,
- .remove = imx_si476x_remove,
-};
-
-module_platform_driver(imx_si476x_driver);
-
-/* Module information */
-MODULE_AUTHOR("Freescale Semiconductor, Inc.");
-MODULE_DESCRIPTION("ALSA SoC i.MX si476x");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-tuner-si476x");
}
}
- dev_dbg(card->dev, "ASoC: can't get %s BE for %s\n",
+ dev_err(card->dev, "ASoC: can't get %s BE for %s\n",
stream ? "capture" : "playback", widget->name);
return NULL;
}
/* is there a valid BE rtd for this widget */
be = dpcm_get_be(card, list->widgets[i], stream);
if (!be) {
- dev_dbg(fe->dev, "ASoC: no BE found for %s\n",
+ dev_err(fe->dev, "ASoC: no BE found for %s\n",
list->widgets[i]->name);
continue;
}