Compare commits
10 Commits
28ae3e81fc
...
c277ad70c7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c277ad70c7 | ||
|
|
b743775076 | ||
|
|
8a2b53c829 | ||
|
|
88dcbe14df | ||
|
|
8f299bac54 | ||
|
|
a62972a55d | ||
|
|
cbde74782d | ||
|
|
294770dc1a | ||
|
|
3896ebad68 | ||
|
|
26109c7443 |
@@ -171,6 +171,28 @@
|
||||
startup-delay-us = <100000>;
|
||||
vin-supply = <&vcc_io>;
|
||||
};
|
||||
|
||||
vcc_cam: vcc-cam {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_cam";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cam_pwr>;
|
||||
enable-active-high;
|
||||
gpio = <&gpio2 0 GPIO_ACTIVE_HIGH>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
vcc_led: vcc-led {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_cam";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cam_mclk>;
|
||||
enable-active-high;
|
||||
gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
&cif_isp0 {
|
||||
@@ -427,22 +449,15 @@
|
||||
&i2c2 {
|
||||
status = "okay";
|
||||
|
||||
camera0: camera-module@10 {
|
||||
camera0: camera-module@36 {
|
||||
status = "okay";
|
||||
compatible = "sony,imx219-v4l2-i2c-subdev";
|
||||
reg = <0x10>;
|
||||
compatible = "ovti,ov7750-v4l2-i2c-subdev";
|
||||
reg = <0x36>;
|
||||
device_type = "v4l2-i2c-subdev";
|
||||
|
||||
clocks = <&cru SCLK_VIP_OUT>;
|
||||
clock-names = "clk_cif_out";
|
||||
|
||||
pinctrl-names = "rockchip,camera_default",
|
||||
"rockchip,camera_sleep";
|
||||
pinctrl-0 = <&cam0_default_pins>;
|
||||
pinctrl-1 = <&cam0_sleep_pins>;
|
||||
|
||||
rockchip,pd-gpio = <&gpio2 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
rockchip,camera-module-mclk-name = "clk_cif_out";
|
||||
rockchip,camera-module-regulator-names = "vcc33_mipi";
|
||||
rockchip,camera-module-regulator-voltages = <3300000>;
|
||||
@@ -489,9 +504,13 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
&spi2 {
|
||||
status = "okay";
|
||||
max-freq = <50000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi2_clk &spi2_tx &spi2_rx &spi2_cs0 &spi2_cs1>;
|
||||
#address-cells = <2>;
|
||||
|
||||
spidev@0 {
|
||||
compatible = "rockchip,spi_tinker";
|
||||
@@ -735,17 +754,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
cam_pins {
|
||||
cam0_default_pins: cam0-default-pins {
|
||||
rockchip,pins = <0 17 RK_FUNC_GPIO &pcfg_pull_none>,
|
||||
<2 0 RK_FUNC_GPIO &pcfg_pull_none>,
|
||||
<2 11 RK_FUNC_1 &pcfg_pull_none>;
|
||||
cam_mclk: cam-mclk {
|
||||
rockchip,pins = <2 11 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
cam0_sleep_pins: cam0-sleep-pins {
|
||||
rockchip,pins = <0 17 RK_FUNC_GPIO &pcfg_pull_none>,
|
||||
<2 0 RK_FUNC_GPIO &pcfg_pull_none>,
|
||||
<2 11 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
cam_pwr: cam-pwr {
|
||||
rockchip,pins = <2 0 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -101,6 +101,8 @@
|
||||
#cooling-cells = <2>; /* min followed by max */
|
||||
dynamic-power-coefficient = <322>;
|
||||
clocks = <&cru ARMCLK>;
|
||||
nvmem-cells = <&package_info>;
|
||||
nvmem-cell-names = "package_info";
|
||||
};
|
||||
cpu1: cpu@501 {
|
||||
device_type = "cpu";
|
||||
@@ -129,63 +131,87 @@
|
||||
compatible = "operating-points-v2";
|
||||
opp-shared;
|
||||
|
||||
nvmem-cells = <&cpu_leakage>;
|
||||
nvmem-cell-names = "cpu_leakage";
|
||||
|
||||
opp-126000000 {
|
||||
opp@126000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <126000000>;
|
||||
opp-microvolt = <900000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-216000000 {
|
||||
opp@216000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <216000000>;
|
||||
opp-microvolt = <900000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-408000000 {
|
||||
opp@408000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <408000000>;
|
||||
opp-microvolt = <900000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-600000000 {
|
||||
opp@600000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <600000000>;
|
||||
opp-microvolt = <900000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-696000000 {
|
||||
opp@696000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <696000000>;
|
||||
opp-microvolt = <950000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-816000000 {
|
||||
opp@816000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <816000000>;
|
||||
opp-microvolt = <1000000>;
|
||||
clock-latency-ns = <40000>;
|
||||
opp-suspend;
|
||||
};
|
||||
opp-1008000000 {
|
||||
opp@1008000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1008000000>;
|
||||
opp-microvolt = <1050000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-1200000000 {
|
||||
opp@1200000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1200000000>;
|
||||
opp-microvolt = <1100000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-1416000000 {
|
||||
opp@1416000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1416000000>;
|
||||
opp-microvolt = <1200000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-1512000000 {
|
||||
opp@1512000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1512000000>;
|
||||
opp-microvolt = <1300000>;
|
||||
opp-microvolt-v1 = <1250000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp-1608000000 {
|
||||
opp@1608000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1608000000>;
|
||||
opp-microvolt = <1350000>;
|
||||
opp-microvolt-v1 = <1300000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp@1704000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1704000000>;
|
||||
opp-microvolt = <1350000>;
|
||||
opp-microvolt-v1 = <1350000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
opp@1800000000 {
|
||||
opp-supported-hw = <0x3>;
|
||||
opp-hz = /bits/ 64 <1800000000>;
|
||||
opp-microvolt = <1350000>;
|
||||
opp-microvolt-v1 = <1400000>;
|
||||
clock-latency-ns = <40000>;
|
||||
};
|
||||
};
|
||||
@@ -964,7 +990,7 @@
|
||||
<&cru PCLK_PERI>;
|
||||
assigned-clock-rates = <594000000>,
|
||||
<500000000>, <300000000>,
|
||||
<150000000>, <75000000>,
|
||||
<0>, <75000000>,
|
||||
<300000000>, <150000000>,
|
||||
<75000000>;
|
||||
};
|
||||
@@ -1186,6 +1212,8 @@
|
||||
resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>;
|
||||
reset-names = "axi", "ahb", "dclk";
|
||||
iommus = <&vopb_mmu>;
|
||||
assigned-clocks = <&cru DCLK_VOP0>;
|
||||
assigned-clock-parents = <&cru PLL_NPLL>;
|
||||
status = "disabled";
|
||||
|
||||
vopb_out: port {
|
||||
@@ -1563,6 +1591,9 @@
|
||||
cpu_leakage: cpu_leakage@17 {
|
||||
reg = <0x17 0x1>;
|
||||
};
|
||||
package_info: package-info {
|
||||
reg = <0x05 0x1>;
|
||||
};
|
||||
};
|
||||
|
||||
gic: interrupt-controller@ffc01000 {
|
||||
|
||||
@@ -502,6 +502,8 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y
|
||||
CONFIG_VIDEO_ROCKCHIP_VPU=y
|
||||
CONFIG_V4L_TEST_DRIVERS=y
|
||||
CONFIG_VIDEO_IMX219=y
|
||||
CONFIG_VIDEO_OV7750=y
|
||||
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_ROCKCHIP=y
|
||||
CONFIG_ROCKCHIP_DW_HDMI=y
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
@@ -33,6 +34,18 @@
|
||||
#define RK3288_GRF_SOC_CON2 0x24C
|
||||
#define RK3288_TIMER6_7_PHYS 0xff810000
|
||||
|
||||
static struct i2c_board_info __initdata i2c_devices_tinker_mcu[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("tinker_mcu", 0x45),
|
||||
},
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata i2c_devices_tinker_ft5406[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("tinker_ft5406", 0x38),
|
||||
},
|
||||
};
|
||||
|
||||
static void __init rockchip_timer_init(void)
|
||||
{
|
||||
if (of_machine_is_compatible("rockchip,rk3288")) {
|
||||
@@ -62,6 +75,9 @@ static void __init rockchip_dt_init(void)
|
||||
rockchip_suspend_init();
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
platform_device_register_simple("cpufreq-dt", 0, NULL, 0);
|
||||
|
||||
i2c_register_board_info(3, i2c_devices_tinker_mcu, ARRAY_SIZE(i2c_devices_tinker_mcu));
|
||||
i2c_register_board_info(3, i2c_devices_tinker_ft5406, ARRAY_SIZE(i2c_devices_tinker_ft5406));
|
||||
}
|
||||
|
||||
static const char * const rockchip_board_dt_compat[] = {
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#define PLL_MODE_DEEP 0x2
|
||||
#define PLL_RK3328_MODE_MASK 0x1
|
||||
|
||||
unsigned long apll_safefreq = ULONG_MAX;
|
||||
unsigned long apll_maxfreq;
|
||||
|
||||
struct rockchip_clk_pll {
|
||||
struct clk_hw hw;
|
||||
|
||||
@@ -52,6 +55,7 @@ struct rockchip_clk_pll {
|
||||
spinlock_t *lock;
|
||||
|
||||
struct rockchip_clk_provider *ctx;
|
||||
u8 id;
|
||||
};
|
||||
|
||||
#define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
|
||||
@@ -645,6 +649,8 @@ static unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw,
|
||||
|
||||
if (pll->sel && pll->scaling)
|
||||
return pll->scaling;
|
||||
if (pll->id == 1 && apll_maxfreq)
|
||||
return apll_maxfreq;
|
||||
|
||||
rockchip_rk3066_pll_get_params(pll, &cur);
|
||||
|
||||
@@ -720,6 +726,7 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
||||
const struct rockchip_pll_rate_table *rate;
|
||||
unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate);
|
||||
unsigned long temp_rate = drate;
|
||||
struct regmap *grf = rockchip_clk_get_grf(pll->ctx);
|
||||
int ret;
|
||||
|
||||
@@ -729,6 +736,9 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
return PTR_ERR(grf);
|
||||
}
|
||||
|
||||
if (pll->id == 1 && drate > apll_safefreq)
|
||||
drate = apll_safefreq;
|
||||
|
||||
pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
|
||||
__func__, clk_hw_get_name(hw), old_rate, drate, prate);
|
||||
|
||||
@@ -743,6 +753,10 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
ret = rockchip_rk3066_pll_set_params(pll, rate);
|
||||
if (ret)
|
||||
pll->scaling = 0;
|
||||
if (!ret && pll->id == 1 && drate == apll_safefreq)
|
||||
apll_maxfreq = temp_rate;
|
||||
else
|
||||
apll_maxfreq = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1268,7 +1282,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
|
||||
u8 num_parents, int con_offset, int grf_lock_offset,
|
||||
int lock_shift, int mode_offset, int mode_shift,
|
||||
struct rockchip_pll_rate_table *rate_table,
|
||||
unsigned long flags, u8 clk_pll_flags)
|
||||
unsigned long flags, u8 clk_pll_flags, u8 id)
|
||||
{
|
||||
const char *pll_parents[3];
|
||||
struct clk_init_data init;
|
||||
@@ -1393,6 +1407,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
|
||||
pll->flags = clk_pll_flags;
|
||||
pll->lock = &ctx->lock;
|
||||
pll->ctx = ctx;
|
||||
pll->id = id;
|
||||
|
||||
pll_clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(pll_clk)) {
|
||||
|
||||
@@ -100,6 +100,29 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
|
||||
RK3066_PLL_RATE( 216000000, 1, 72, 8),
|
||||
RK3066_PLL_RATE( 148500000, 2, 99, 8),
|
||||
RK3066_PLL_RATE( 126000000, 1, 84, 16),
|
||||
RK3066_PLL_RATE_NB( 241500000, 2, 161, 8, 1),
|
||||
RK3066_PLL_RATE( 252000000, 1, 84, 8),
|
||||
RK3066_PLL_RATE( 216000000, 1, 72, 8),
|
||||
RK3066_PLL_RATE( 148500000, 8, 693, 14),
|
||||
RK3066_PLL_RATE( 135000000, 4, 315, 14),
|
||||
RK3066_PLL_RATE( 126000000, 1, 84, 16),
|
||||
RK3066_PLL_RATE( 119000000, 3, 238, 16),
|
||||
RK3066_PLL_RATE( 108000000, 1, 72, 16),
|
||||
RK3066_PLL_RATE( 88750000, 6, 355, 16),
|
||||
RK3066_PLL_RATE( 71000000, 3, 142, 16),
|
||||
RK3066_PLL_RATE( 74250000, 8, 297, 12),
|
||||
RK3066_PLL_RATE( 78750000, 4, 210, 16),
|
||||
RK3066_PLL_RATE( 78800000, 15, 788, 16),
|
||||
RK3066_PLL_RATE( 75000000, 2, 100, 16),
|
||||
RK3066_PLL_RATE( 65000000, 3, 130, 16),
|
||||
RK3066_PLL_RATE( 136750000, 8, 547, 12),
|
||||
RK3066_PLL_RATE( 106500000, 1, 71, 16),
|
||||
RK3066_PLL_RATE( 88750000, 6, 355, 16),
|
||||
RK3066_PLL_RATE( 67500000, 8, 315, 14),
|
||||
RK3066_PLL_RATE( 49500000, 1, 33, 16),
|
||||
RK3066_PLL_RATE( 40000000, 3, 80, 16),
|
||||
RK3066_PLL_RATE( 36000000, 1, 24, 16),
|
||||
RK3066_PLL_RATE( 35500000, 3, 71, 16),
|
||||
RK3066_PLL_RATE( 48000000, 1, 64, 32),
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
@@ -211,9 +234,9 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = {
|
||||
[cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3288_PLL_CON(8),
|
||||
RK3288_MODE_CON, 8, 7, 0, rk3288_pll_rates),
|
||||
[gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12),
|
||||
RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
|
||||
RK3288_MODE_CON, 12, 8, 0, rk3288_pll_rates),
|
||||
[npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16),
|
||||
RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates),
|
||||
RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates),
|
||||
};
|
||||
|
||||
static struct clk_div_table div_hclk_cpu_t[] = {
|
||||
@@ -428,7 +451,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
||||
RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RK3288_CLKGATE_CON(3), 4, GFLAGS),
|
||||
|
||||
COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0,
|
||||
COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||
RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS,
|
||||
RK3288_CLKGATE_CON(3), 1, GFLAGS),
|
||||
COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0,
|
||||
|
||||
@@ -393,7 +393,7 @@ void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
|
||||
list->con_offset, grf_lock_offset,
|
||||
list->lock_shift, list->mode_offset,
|
||||
list->mode_shift, list->rate_table,
|
||||
list->flags, list->pll_flags);
|
||||
list->flags, list->pll_flags, list->id);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: failed to register clock %s\n", __func__,
|
||||
list->name);
|
||||
|
||||
@@ -261,7 +261,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
|
||||
u8 num_parents, int con_offset, int grf_lock_offset,
|
||||
int lock_shift, int mode_offset, int mode_shift,
|
||||
struct rockchip_pll_rate_table *rate_table,
|
||||
unsigned long flags, u8 clk_pll_flags);
|
||||
unsigned long flags, u8 clk_pll_flags, u8 id);
|
||||
|
||||
struct rockchip_cpuclk_clksel {
|
||||
int reg;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -30,6 +31,10 @@
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#define MAX_CLUSTERS 2
|
||||
#define MAX_PROP_NAME_LEN 6
|
||||
#define VERSION_ELEMENTS 1
|
||||
#define INVALID_VALUE 0xff
|
||||
#define SAFE_FREQ (24 * 67 * 1000000)
|
||||
|
||||
struct private_data {
|
||||
struct device *cpu_dev;
|
||||
@@ -43,6 +48,8 @@ static struct freq_attr *cpufreq_dt_attr[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static unsigned char package_info = INVALID_VALUE;
|
||||
extern unsigned long apll_safefreq;
|
||||
static int set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
struct private_data *priv = policy->driver_data;
|
||||
@@ -51,6 +58,87 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
policy->freq_table[index].frequency * 1000);
|
||||
}
|
||||
|
||||
static int fetch_package_info(struct device *dev, unsigned char *package_info)
|
||||
{
|
||||
struct nvmem_cell *cell;
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
|
||||
cell = nvmem_cell_get(dev, "package_info");
|
||||
if (IS_ERR(cell))
|
||||
return PTR_ERR(cell);
|
||||
|
||||
buf = (unsigned char *)nvmem_cell_read(cell, &len);
|
||||
|
||||
nvmem_cell_put(cell);
|
||||
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
if (buf[0] == INVALID_VALUE)
|
||||
return -EINVAL;
|
||||
|
||||
*package_info = buf[0];
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_opp_info(struct device *dev)
|
||||
{
|
||||
struct device_node *opp_np, *np;
|
||||
unsigned char chip_vesion;
|
||||
char name[MAX_PROP_NAME_LEN];
|
||||
unsigned int version;
|
||||
unsigned int count = 0;
|
||||
int ret;
|
||||
|
||||
if (package_info == INVALID_VALUE) {
|
||||
dev_info(dev, "package_info NULL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
opp_np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
|
||||
if (!opp_np)
|
||||
return 0;
|
||||
for_each_available_child_of_node(opp_np, np) {
|
||||
ret = of_property_read_u32_index(np, "opp-supported-hw",
|
||||
VERSION_ELEMENTS - 1,
|
||||
&version);
|
||||
if (!ret) {
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
if ((package_info & 0xc0) == 0xc0) {
|
||||
chip_vesion = 1;
|
||||
apll_safefreq = ULONG_MAX;
|
||||
} else {
|
||||
chip_vesion = 0;
|
||||
apll_safefreq = SAFE_FREQ;
|
||||
}
|
||||
snprintf(name, MAX_PROP_NAME_LEN, "v%d", chip_vesion);
|
||||
ret = dev_pm_opp_set_prop_name(dev, name);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set prop name\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
version = BIT(chip_vesion);
|
||||
ret = dev_pm_opp_set_supported_hw(dev, &version, VERSION_ELEMENTS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set supported hardware\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "chip_version: %d 0x%x\n", chip_vesion, version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* An earlier version of opp-v1 bindings used to name the regulator
|
||||
* "cpu0-supply", we still need to handle that for backwards compatibility.
|
||||
@@ -141,6 +229,11 @@ static int resources_available(void)
|
||||
}
|
||||
|
||||
regulator_put(cpu_reg);
|
||||
|
||||
ret = fetch_package_info(cpu_dev, &package_info);
|
||||
if (ret)
|
||||
dev_dbg(cpu_dev, "Failed to fetch wafer_info\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -151,9 +244,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
||||
struct device *cpu_dev;
|
||||
struct clk *cpu_clk;
|
||||
struct dev_pm_opp *suspend_opp;
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
struct cpumask cpus;
|
||||
#endif
|
||||
|
||||
unsigned int transition_latency;
|
||||
unsigned long cur_freq;
|
||||
bool opp_v1 = false;
|
||||
@@ -187,6 +279,12 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
||||
goto out_put_clk;
|
||||
}
|
||||
|
||||
if (!opp_v1) {
|
||||
ret = set_opp_info(cpu_dev);
|
||||
if (ret)
|
||||
dev_err(cpu_dev, "Failed to set_opp_info: %d\n", ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* OPP layer will be taking care of regulators now, but it needs to know
|
||||
* the name of the regulator first.
|
||||
@@ -211,7 +309,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
||||
*
|
||||
* OPPs might be populated at runtime, don't check for error here
|
||||
*/
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
ret = dev_pm_opp_of_add_table(cpu_dev);
|
||||
if (ret) {
|
||||
dev_err(cpu_dev, "couldn't find opp table for cpu:%d, %d\n",
|
||||
@@ -224,9 +321,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
||||
dev_pm_opp_of_remove_table(cpu_dev);
|
||||
}
|
||||
}
|
||||
#else
|
||||
dev_pm_opp_of_cpumask_add_table(policy->cpus);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* But we need OPP table to function so if it is not there let's
|
||||
@@ -329,12 +423,11 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
|
||||
struct cpumask cpus;
|
||||
struct private_data *priv = policy->driver_data;
|
||||
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
cpumask_set_cpu(policy->cpu, policy->cpus);
|
||||
if (cpufreq_generic_suspend(policy))
|
||||
pr_err("%s: Failed to suspend driver: %p\n", __func__, policy);
|
||||
cpumask_clear_cpu(policy->cpu, policy->cpus);
|
||||
#endif
|
||||
|
||||
priv->cpu_dev = get_cpu_device(policy->cpu);
|
||||
cpufreq_cooling_unregister(priv->cdev);
|
||||
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
|
||||
|
||||
@@ -83,9 +83,9 @@
|
||||
|
||||
#define ov7750_EXP_VALID_FRAMES 4
|
||||
/* High byte of product ID */
|
||||
#define ov7750_PIDH_MAGIC 0x77
|
||||
#define ov7750_PIDH_MAGIC 0x56
|
||||
/* Low byte of product ID */
|
||||
#define ov7750_PIDL_MAGIC 0x50
|
||||
#define ov7750_PIDL_MAGIC 0x47
|
||||
|
||||
#define BG_RATIO_TYPICAL 0x129
|
||||
#define RG_RATIO_TYPICAL 0x11f
|
||||
@@ -102,221 +102,108 @@ static struct ov_camera_module_custom_config ov7750_custom_config;
|
||||
|
||||
// The settings may be altered by the code in IsiSetupSensor.
|
||||
static struct ov_camera_module_reg ov7750_init_tab_640_480_60fps[] = {
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0103, 0x01},// enable soft reset
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},// stream off
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3005, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3012, 0xc0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3013, 0xd2},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3014, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3016, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3017, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x301a, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x301b, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x301c, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3023, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3037, 0xf0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3098, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3099, 0x14},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x309a, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x309b, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x30b0, 0x0a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x30b1, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x30b3, 0x32},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x30b4, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x30b5, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3106, 0xda},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x1f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x80},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x07},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3509, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350b, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x1c},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3602, 0x62},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3620, 0xb7},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3622, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3626, 0x21},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3627, 0x30},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3630, 0x44},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3631, 0x35},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x60},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3662, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3663, 0x70},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3664, 0xf0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3666, 0x0a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3669, 0x1a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x366a, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x366b, 0x50},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3673, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3674, 0xff},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3675, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0xc1},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x40},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373c, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3742, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3757, 0xb3},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3788, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a8, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a9, 0xc0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0x8b},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xeb},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3000, 0x0f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3001, 0xff},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3002, 0xe4},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0103, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3034, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3035, 0x21},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3036, 0x46},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x303c, 0x11},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3106, 0xf5},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x07},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x41},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3827, 0xec},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370c, 0x0f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3612, 0x59},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3618, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0x06},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5002, 0x41},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5003, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5a00, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3000, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3001, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3002, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3016, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3017, 0xe0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x44},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x301c, 0xf8},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x301d, 0xf0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a18, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a19, 0xf8},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c01, 0x80},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b07, 0x0c},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x07},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x68},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xd8},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x31},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x31},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3708, 0x64},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x52},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x80},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xe0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0xa0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0x1a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3812, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x11},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x11},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x40},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382f, 0x0e},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3832, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3833, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3834, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3835, 0x0c},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3837, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x38b1, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b80, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b81, 0xa5},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b82, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b83, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b84, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b85, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b86, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b87, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b88, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b89, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b8a, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b8b, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b8c, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b8d, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b8e, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b8f, 0x1a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b94, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b95, 0xf2},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3b96, 0x40},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c00, 0x89},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c01, 0x63},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c02, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c03, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c04, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c05, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c06, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c07, 0x06},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c0c, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c0d, 0xd0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c0e, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3c0f, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x42},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4004, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4005, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x404e, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4241, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4242, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4300, 0xff},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4301, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4501, 0x48},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0x4e},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4801, 0x0f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4806, 0x0f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4819, 0xaa},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4823, 0x3e},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4837, 0x19},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4a0d, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4a47, 0x7f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4a49, 0xf0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4a4b, 0x30},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0x85},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x80},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x1f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x80},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x07},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3509, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350b, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x1c},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3602, 0x62},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3620, 0xb7},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3622, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3626, 0x21},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3627, 0x30},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3630, 0x44},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3631, 0x35},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x60},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3662, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3663, 0x70},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3664, 0xf0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3666, 0x0a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3669, 0x1a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x366a, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x366b, 0x50},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3673, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3674, 0xff},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3675, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0xc1},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x40},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373c, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3742, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3757, 0xb3},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3788, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a8, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a9, 0xc0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xE0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0x8b},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xeb},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x80},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xe0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0xa0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0x1a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3812, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x11},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x11},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x40},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382f, 0x0e},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3832, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3833, 0x05},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3834, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3835, 0x0c},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3837, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x0a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0x3f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x07},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xa1},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x08},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3630, 0x2e},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3632, 0xe2},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3633, 0x23},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x44},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x06},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3620, 0x64},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3621, 0xe0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x37},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3704, 0xa0},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3703, 0x5a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3715, 0x78},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3717, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3731, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0x60},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0x1a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f05, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f06, 0x10},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f01, 0x0a},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a08, 0x01},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a09, 0x27},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a0a, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a0b, 0xf6},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a0d, 0x04},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a0e, 0x03},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a0f, 0x58},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a10, 0x50},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1b, 0x58},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1e, 0x50},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a11, 0x60},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1f, 0x28},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4004, 0x02},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4000, 0x09},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4837, 0x24},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4050, 0x6e},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4051, 0x8f},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4202, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x300D, 0x00},
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4800, 0x25},
|
||||
};
|
||||
|
||||
static struct ov_camera_module_config ov7750_configs[] = {
|
||||
{
|
||||
{OV_CAMERA_MODULE_REG_TYPE_DATA,
|
||||
.name = "640x480_60fps",
|
||||
.frm_fmt = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.code = MEDIA_BUS_FMT_SBGGR10_1X10
|
||||
.code = MEDIA_BUS_FMT_SBGGR8_1X8
|
||||
},
|
||||
.frm_intrvl = {
|
||||
.interval = {
|
||||
@@ -334,7 +221,7 @@ static struct ov_camera_module_config ov7750_configs[] = {
|
||||
.reg_diff_table = NULL,
|
||||
.reg_diff_table_num_entries = 0,
|
||||
.v_blanking_time_us = 7251,
|
||||
PLTFRM_CAM_ITF_MIPI_CFG(0, 1, 800, 24000000)
|
||||
PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 800, 24000000)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -367,98 +254,6 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov7750_auto_adjust_fps(struct ov_camera_module *cam_mod,
|
||||
u32 exp_time)
|
||||
{
|
||||
int ret;
|
||||
u32 vts;
|
||||
|
||||
if ((cam_mod->exp_config.exp_time + ov7750_COARSE_INTG_TIME_MAX_MARGIN)
|
||||
> cam_mod->vts_min)
|
||||
vts = cam_mod->exp_config.exp_time +
|
||||
ov7750_COARSE_INTG_TIME_MAX_MARGIN;
|
||||
else
|
||||
vts = cam_mod->vts_min;
|
||||
ret = ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_TIMING_VTS_LOW_REG,
|
||||
vts & 0xFF);
|
||||
ret |= ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_TIMING_VTS_HIGH_REG,
|
||||
(vts >> 8) & 0xFF);
|
||||
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
ov_camera_module_pr_err(cam_mod,
|
||||
"failed with error (%d)\n", ret);
|
||||
} else {
|
||||
ov_camera_module_pr_debug(cam_mod,
|
||||
"updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min);
|
||||
cam_mod->vts_cur = vts;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov7750_write_aec(struct ov_camera_module *cam_mod)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ov_camera_module_pr_debug(cam_mod,
|
||||
"exp_time = %d, gain = %d, flash_mode = %d\n",
|
||||
cam_mod->exp_config.exp_time,
|
||||
cam_mod->exp_config.gain,
|
||||
cam_mod->exp_config.flash_mode);
|
||||
|
||||
/*
|
||||
* if the sensor is already streaming, write to shadow registers,
|
||||
* if the sensor is in SW standby, write to active registers,
|
||||
* if the sensor is off/registers are not writeable, do nothing
|
||||
*/
|
||||
if ((cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY) ||
|
||||
(cam_mod->state == OV_CAMERA_MODULE_STREAMING)) {
|
||||
u32 a_gain = cam_mod->exp_config.gain;
|
||||
u32 exp_time;
|
||||
|
||||
a_gain = a_gain > 0x7ff ? 0x7ff : a_gain;
|
||||
a_gain = a_gain * cam_mod->exp_config.gain_percent / 100;
|
||||
exp_time = cam_mod->exp_config.exp_time << 4;
|
||||
if (cam_mod->state == OV_CAMERA_MODULE_STREAMING)
|
||||
ret = ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_GROUP_UPDATE_ADDRESS,
|
||||
ov7750_AEC_GROUP_UPDATE_START_DATA);
|
||||
if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps)
|
||||
ret = ov7750_auto_adjust_fps(cam_mod,
|
||||
cam_mod->exp_config.exp_time);
|
||||
ret |= ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_PK_LONG_GAIN_HIGH_REG,
|
||||
ov7750_FETCH_MSB_GAIN(a_gain));
|
||||
ret |= ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_PK_LONG_GAIN_LOW_REG,
|
||||
ov7750_FETCH_LSB_GAIN(a_gain));
|
||||
ret = ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_PK_LONG_EXPO_3RD_REG,
|
||||
ov7750_FETCH_3RD_BYTE_EXP(exp_time));
|
||||
ret |= ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_PK_LONG_EXPO_2ND_REG,
|
||||
ov7750_FETCH_2ND_BYTE_EXP(exp_time));
|
||||
ret |= ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_PK_LONG_EXPO_1ST_REG,
|
||||
ov7750_FETCH_1ST_BYTE_EXP(exp_time));
|
||||
if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) {
|
||||
ret = ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_GROUP_UPDATE_ADDRESS,
|
||||
ov7750_AEC_GROUP_UPDATE_END_DATA);
|
||||
ret = ov_camera_module_write_reg(cam_mod,
|
||||
ov7750_AEC_GROUP_UPDATE_ADDRESS,
|
||||
ov7750_AEC_GROUP_UPDATE_END_LAUNCH);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ERR_VALUE(ret))
|
||||
ov_camera_module_pr_err(cam_mod,
|
||||
"failed with error (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov7750_g_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -685,7 +480,6 @@ static int ov7750_s_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
|
||||
switch (ctrl_id) {
|
||||
case V4L2_CID_GAIN:
|
||||
case V4L2_CID_EXPOSURE:
|
||||
ret = ov7750_write_aec(cam_mod);
|
||||
break;
|
||||
case V4L2_CID_FLASH_LED_MODE:
|
||||
/* nothing to be done here */
|
||||
@@ -706,88 +500,12 @@ static int ov7750_s_ext_ctrls(struct ov_camera_module *cam_mod,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Handles only exposure and gain together special case. */
|
||||
if (ctrls->count == 1)
|
||||
ret = ov7750_s_ctrl(cam_mod, ctrls->ctrls[0].id);
|
||||
else if ((ctrls->count == 3) &&
|
||||
((ctrls->ctrls[0].id == V4L2_CID_GAIN &&
|
||||
ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) ||
|
||||
(ctrls->ctrls[1].id == V4L2_CID_GAIN &&
|
||||
ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)))
|
||||
ret = ov7750_write_aec(cam_mod);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
if (IS_ERR_VALUE(ret))
|
||||
ov_camera_module_pr_debug(cam_mod,
|
||||
"failed with error (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov7750_set_flip(
|
||||
struct ov_camera_module *cam_mod,
|
||||
struct pltfrm_camera_module_reg reglist[],
|
||||
int len)
|
||||
{
|
||||
int i, mode = 0;
|
||||
u16 match_reg[2];
|
||||
|
||||
mode = ov_camera_module_get_flip_mirror(cam_mod);
|
||||
if (mode == -1) {
|
||||
ov_camera_module_pr_info(cam_mod,
|
||||
"dts don't set flip, return!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(cam_mod->active_config)) {
|
||||
switch (cam_mod->active_config->frm_fmt.width) {
|
||||
case ov7750_FULL_SIZE_RESOLUTION_WIDTH:
|
||||
if (mode == OV_FLIP_BIT_MASK) {
|
||||
match_reg[0] = 0x06;
|
||||
match_reg[1] = 0x00;
|
||||
} else if (mode == OV_MIRROR_BIT_MASK) {
|
||||
match_reg[0] = 0x00;
|
||||
match_reg[1] = 0x06;
|
||||
} else if (mode == (OV_MIRROR_BIT_MASK |
|
||||
OV_FLIP_BIT_MASK)) {
|
||||
match_reg[0] = 0x06;
|
||||
match_reg[1] = 0x06;
|
||||
} else {
|
||||
match_reg[0] = 0x00;
|
||||
match_reg[1] = 0x00;
|
||||
}
|
||||
break;
|
||||
case ov7750_BINING_SIZE_RESOLUTION_WIDTH:
|
||||
if (mode == OV_FLIP_BIT_MASK) {
|
||||
match_reg[0] = 0x16;
|
||||
match_reg[1] = 0x01;
|
||||
} else if (mode == OV_MIRROR_BIT_MASK) {
|
||||
match_reg[0] = 0x16;
|
||||
match_reg[1] = 0x07;
|
||||
} else if (mode == (OV_MIRROR_BIT_MASK |
|
||||
OV_FLIP_BIT_MASK)) {
|
||||
match_reg[0] = 0x16;
|
||||
match_reg[1] = 0x07;
|
||||
} else {
|
||||
match_reg[0] = 0x10;
|
||||
match_reg[1] = 0x01;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = len; i > 0; i--) {
|
||||
if (reglist[i].reg == ov7750_FLIP_REG)
|
||||
reglist[i].val = match_reg[0];
|
||||
else if (reglist[i].reg == ov7750_MIRROR_REG)
|
||||
reglist[i].val = match_reg[1];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov7750_start_streaming(struct ov_camera_module *cam_mod)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -799,6 +517,11 @@ static int ov7750_start_streaming(struct ov_camera_module *cam_mod)
|
||||
if (IS_ERR_VALUE(ret))
|
||||
goto err;
|
||||
|
||||
ret = ov_camera_module_write_reg(cam_mod, 0x4800, 0x04);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
goto err;
|
||||
|
||||
|
||||
if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1)))
|
||||
goto err;
|
||||
|
||||
@@ -817,6 +540,11 @@ static int ov7750_stop_streaming(struct ov_camera_module *cam_mod)
|
||||
|
||||
ov_camera_module_pr_debug(cam_mod, "\n");
|
||||
|
||||
ret = ov_camera_module_write_reg(cam_mod, 0x4800, 0x25);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
goto err;
|
||||
|
||||
|
||||
ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
goto err;
|
||||
@@ -899,7 +627,6 @@ static struct ov_camera_module_custom_config ov7750_custom_config = {
|
||||
.g_ctrl = ov7750_g_ctrl,
|
||||
.g_timings = ov7750_g_timings,
|
||||
.check_camera_id = ov7750_check_camera_id,
|
||||
.set_flip = ov7750_set_flip,
|
||||
.configs = ov7750_configs,
|
||||
.num_configs = ARRAY_SIZE(ov7750_configs),
|
||||
.power_up_delays_ms = {5, 20, 0}
|
||||
@@ -936,8 +663,8 @@ static int ov7750_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ov7750_id[] = {
|
||||
{ ov7750_DRIVER_NAME, 0 },
|
||||
{ }
|
||||
{ov7750_DRIVER_NAME, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct of_device_id ov7750_of_match[] = {
|
||||
|
||||
@@ -1241,7 +1241,7 @@ int cif_isp10_pltfrm_dev_init(
|
||||
pdata->irq_handlers[i].mis = -EINVAL;
|
||||
|
||||
#ifdef CIF_ISP10_MODE_DMA_SG
|
||||
np = of_find_node_by_name(NULL, "isp0_mmu");
|
||||
np = of_find_node_by_name(NULL, "isp_mmu");
|
||||
if (!np) {
|
||||
int index = 0;
|
||||
/* iommu domain */
|
||||
|
||||
@@ -27,3 +27,17 @@ config ROCKCHIP_DW_MIPI_DSI2
|
||||
for the Synopsys DesignWare HDMI driver. If you want to
|
||||
enable MIPI DSI on RK3288 based SoC, you should selet this
|
||||
option.
|
||||
|
||||
config TINKER_MCU
|
||||
tristate "tinker mcu"
|
||||
default y
|
||||
depends on I2C
|
||||
help
|
||||
Control the power of touch screen for tinker board.
|
||||
|
||||
config TOUCHSCREEN_TINKER_FT5406
|
||||
tristate "tinker ft5406"
|
||||
default y
|
||||
depends on I2C
|
||||
help
|
||||
Control ft5406 touch ic.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
obj-$(CONFIG_DRM_PANEL_TOSHIBA_TC358762) += panel-toshiba-tc358762.o
|
||||
obj-$(CONFIG_ASUS_RPI_MCU) += asus_mcu.o
|
||||
obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) += dw-mipi-dsi.o
|
||||
obj-$(CONFIG_TINKER_MCU) += tinker_mcu.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TINKER_FT5406) += tinker_ft5406.o
|
||||
|
||||
323
drivers/miniarm/dsi/tinker_ft5406.c
Normal file
323
drivers/miniarm/dsi/tinker_ft5406.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
*
|
||||
* TINKER BOARD FT5406 touch driver.
|
||||
*
|
||||
* Copyright (c) 2016 ASUSTek Computer Inc.
|
||||
* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include "tinker_ft5406.h"
|
||||
|
||||
static int fts_i2c_read(struct i2c_client *client, char *writebuf,
|
||||
int writelen, char *readbuf, int readlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (writelen > 0) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = writelen,
|
||||
.buf = writebuf,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 2);
|
||||
if (ret < 0)
|
||||
LOG_ERR("i2c read error, %d\n", ret);
|
||||
} else {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = readlen,
|
||||
.buf = readbuf,
|
||||
},
|
||||
};
|
||||
ret = i2c_transfer(client->adapter, msgs, 1);
|
||||
if (ret < 0)
|
||||
LOG_ERR("i2c read error, %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fts_read_reg(struct i2c_client *client, u8 addr, u8 *val)
|
||||
{
|
||||
return fts_i2c_read(client, &addr, 1, val, 1);
|
||||
}
|
||||
|
||||
static int fts_check_fw_ver(struct i2c_client *client)
|
||||
{
|
||||
u8 reg_addr, fw_ver[3];
|
||||
int ret;
|
||||
|
||||
reg_addr = FT_REG_FW_VER;
|
||||
ret = fts_i2c_read(client, ®_addr, 1, &fw_ver[0], 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
reg_addr = FT_REG_FW_MIN_VER;
|
||||
ret = fts_i2c_read(client, ®_addr, 1, &fw_ver[1], 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
reg_addr = FT_REG_FW_SUB_MIN_VER;
|
||||
ret = fts_i2c_read(client, ®_addr, 1, &fw_ver[2], 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
LOG_INFO("Firmware version = %d.%d.%d\n", fw_ver[0], fw_ver[1], fw_ver[2]);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fts_read_td_status(struct tinker_ft5406_data *ts_data)
|
||||
{
|
||||
u8 td_status;
|
||||
int ret = -1;
|
||||
ret = fts_read_reg(ts_data->client, FT_TD_STATUS_REG, &td_status);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("get reg td_status failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return (int)td_status;
|
||||
}
|
||||
|
||||
static int fts_read_touchdata(struct tinker_ft5406_data *ts_data)
|
||||
{
|
||||
struct ts_event *event = &ts_data->event;
|
||||
int ret = -1, i;
|
||||
u8 buf[FT_ONE_TCH_LEN-2] = { 0 };
|
||||
u8 reg_addr, pointid = FT_MAX_ID;
|
||||
|
||||
for (i = 0; i < event->touch_point && i < MAX_TOUCH_POINTS; i++) {
|
||||
reg_addr = FT_TOUCH_X_H_REG + (i * FT_ONE_TCH_LEN);
|
||||
ret = fts_i2c_read(ts_data->client, ®_addr, 1, buf, FT_ONE_TCH_LEN-2);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("read touchdata failed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pointid = (buf[FT_TOUCH_ID]) >> 4;
|
||||
if (pointid >= MAX_TOUCH_POINTS)
|
||||
break;
|
||||
event->au8_finger_id[i] = pointid;
|
||||
event->au16_x[i] = (s16) (buf[FT_TOUCH_X_H] & 0x0F) << 8 | (s16) buf[FT_TOUCH_X_L];
|
||||
event->au16_y[i] = (s16) (buf[FT_TOUCH_Y_H] & 0x0F) << 8 | (s16) buf[FT_TOUCH_Y_L];
|
||||
event->au8_touch_event[i] = buf[FT_TOUCH_EVENT] >> 6;
|
||||
|
||||
#if XY_REVERSE
|
||||
event->au16_x[i] = SCREEN_WIDTH - event->au16_x[i] - 1;
|
||||
event->au16_y[i] = SCREEN_HEIGHT - event->au16_y[i] - 1;
|
||||
#endif
|
||||
}
|
||||
event->pressure = FT_PRESS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fts_report_value(struct tinker_ft5406_data *ts_data)
|
||||
{
|
||||
struct ts_event *event = &ts_data->event;
|
||||
int i, modified_ids = 0, released_ids;
|
||||
|
||||
for (i = 0; i < event->touch_point && i < MAX_TOUCH_POINTS; i++) {
|
||||
if (event->au8_touch_event[i]== FT_TOUCH_DOWN
|
||||
|| event->au8_touch_event[i] == FT_TOUCH_CONTACT)
|
||||
{
|
||||
modified_ids |= 1 << event->au8_finger_id[i];
|
||||
input_mt_slot(ts_data->input_dev, event->au8_finger_id[i]);
|
||||
input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER,
|
||||
true);
|
||||
input_report_abs(ts_data->input_dev, ABS_MT_TOUCH_MAJOR,
|
||||
event->pressure);
|
||||
input_report_abs(ts_data->input_dev, ABS_MT_POSITION_X,
|
||||
event->au16_x[i]);
|
||||
input_report_abs(ts_data->input_dev, ABS_MT_POSITION_Y,
|
||||
event->au16_y[i]);
|
||||
|
||||
if(!((1 << event->au8_finger_id[i]) & ts_data->known_ids))
|
||||
LOG_DBG("Touch id-%d: x = %d, y = %d\n",
|
||||
event->au8_finger_id[i], event->au16_x[i], event->au16_y[i]);
|
||||
}
|
||||
}
|
||||
|
||||
released_ids = ts_data->known_ids & ~modified_ids;
|
||||
for(i = 0; released_ids && i < MAX_TOUCH_POINTS; i++) {
|
||||
if(released_ids & (1<<i)) {
|
||||
LOG_DBG("Release id-%d, known = %x modified = %x\n", i, ts_data->known_ids, modified_ids);
|
||||
input_mt_slot(ts_data->input_dev, i);
|
||||
input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, false);
|
||||
modified_ids &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
ts_data->known_ids = modified_ids;
|
||||
input_mt_report_pointer_emulation(ts_data->input_dev, true);
|
||||
input_sync(ts_data->input_dev);
|
||||
}
|
||||
|
||||
extern int tinker_mcu_is_connected(void);
|
||||
|
||||
static void tinker_ft5406_work(struct work_struct *work)
|
||||
{
|
||||
struct tinker_ft5406_data *ts_data
|
||||
= container_of(work, struct tinker_ft5406_data, ft5406_work);
|
||||
struct ts_event *event = &ts_data->event;
|
||||
int ret = 0, count = 8, td_status;
|
||||
|
||||
while(count > 0) {
|
||||
ret = fts_check_fw_ver(ts_data->client);
|
||||
if (ret == 0)
|
||||
break;
|
||||
LOG_INFO("checking touch ic, countdown: %d\n", count);
|
||||
msleep(1000);
|
||||
count--;
|
||||
}
|
||||
if (!count) {
|
||||
LOG_ERR("checking touch ic timeout, %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
//polling 60fps
|
||||
while(1) {
|
||||
td_status = fts_read_td_status(ts_data);
|
||||
if (td_status < VALID_TD_STATUS_VAL+1 && (td_status > 0 || ts_data->known_ids != 0)) {
|
||||
memset(event, -1, sizeof(struct ts_event));
|
||||
event->touch_point = td_status;
|
||||
ret = fts_read_touchdata(ts_data);
|
||||
if (ret == 0)
|
||||
fts_report_value(ts_data);
|
||||
}
|
||||
msleep_interruptible(17);
|
||||
}
|
||||
}
|
||||
|
||||
static int tinker_ft5406_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tinker_ft5406_data *ts_data;
|
||||
struct input_dev *input_dev;
|
||||
int ret = 0, timeout = 10;
|
||||
|
||||
LOG_INFO("address = 0x%x\n", client->addr);
|
||||
|
||||
ts_data = kzalloc(sizeof(struct tinker_ft5406_data), GFP_KERNEL);
|
||||
if (ts_data == NULL) {
|
||||
LOG_ERR("no memory for device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ts_data->client = client;
|
||||
i2c_set_clientdata(client, ts_data);
|
||||
|
||||
while(!tinker_mcu_is_connected() && timeout > 0) {
|
||||
msleep(50);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
LOG_ERR("wait connected timeout\n");
|
||||
ret = -ENODEV;
|
||||
goto timeout_failed;
|
||||
}
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
LOG_ERR("failed to allocate input device\n");
|
||||
goto input_allocate_failed;
|
||||
}
|
||||
input_dev->name = "fts_ts";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &ts_data->client->dev;
|
||||
|
||||
ts_data->input_dev = input_dev;
|
||||
input_set_drvdata(input_dev, ts_data);
|
||||
|
||||
__set_bit(EV_SYN, input_dev->evbit);
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
__set_bit(EV_ABS, input_dev->evbit);
|
||||
__set_bit(BTN_TOUCH, input_dev->keybit);
|
||||
|
||||
input_mt_init_slots(input_dev, MAX_TOUCH_POINTS, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
|
||||
SCREEN_WIDTH, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
|
||||
SCREEN_HEIGHT, 0, 0);
|
||||
|
||||
ret = input_register_device(input_dev);
|
||||
if (ret) {
|
||||
LOG_ERR("Input device registration failed\n");
|
||||
goto input_register_failed;
|
||||
}
|
||||
|
||||
INIT_WORK(&ts_data->ft5406_work, tinker_ft5406_work);
|
||||
schedule_work(&ts_data->ft5406_work);
|
||||
|
||||
return 0;
|
||||
|
||||
input_register_failed:
|
||||
input_free_device(input_dev);
|
||||
input_allocate_failed:
|
||||
timeout_failed:
|
||||
kfree(ts_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tinker_ft5406_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tinker_ft5406_data *ts_data = i2c_get_clientdata(client);
|
||||
|
||||
cancel_work_sync(&ts_data->ft5406_work);
|
||||
if (ts_data->input_dev) {
|
||||
input_unregister_device(ts_data->input_dev);
|
||||
input_free_device(ts_data->input_dev);
|
||||
}
|
||||
kfree(ts_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tinker_ft5406_id[] = {
|
||||
{"tinker_ft5406", 0},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct i2c_driver tinker_ft5406_driver = {
|
||||
.driver = {
|
||||
.name = "tinker_ft5406",
|
||||
},
|
||||
.probe = tinker_ft5406_probe,
|
||||
.remove = tinker_ft5406_remove,
|
||||
.id_table = tinker_ft5406_id,
|
||||
};
|
||||
module_i2c_driver(tinker_ft5406_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TINKER BOARD FT5406 Touch driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
64
drivers/miniarm/dsi/tinker_ft5406.h
Normal file
64
drivers/miniarm/dsi/tinker_ft5406.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef _TINKER_FT5406_H_
|
||||
#define _TINKER_FT5406_H_
|
||||
|
||||
#define LOG_DBG(fmt,arg...) pr_debug("tinker-ft5406: %s: "fmt, __func__, ##arg);
|
||||
#define LOG_INFO(fmt,arg...) pr_info("tinker-ft5406: %s: "fmt, __func__, ##arg);
|
||||
#define LOG_ERR(fmt,arg...) pr_err("tinker-ft5406: %s: "fmt, __func__, ##arg);
|
||||
|
||||
#define XY_REVERSE 1
|
||||
|
||||
#define SCREEN_WIDTH 800
|
||||
#define SCREEN_HEIGHT 480
|
||||
|
||||
#define FT_ONE_TCH_LEN 6
|
||||
|
||||
#define FT_REG_FW_VER 0xA6
|
||||
#define FT_REG_FW_MIN_VER 0xB2
|
||||
#define FT_REG_FW_SUB_MIN_VER 0xB3
|
||||
|
||||
#define VALID_TD_STATUS_VAL 10
|
||||
#define MAX_TOUCH_POINTS 1
|
||||
|
||||
#define FT_PRESS 0x7F
|
||||
#define FT_MAX_ID 0x0F
|
||||
|
||||
#define FT_TOUCH_X_H 0
|
||||
#define FT_TOUCH_X_L 1
|
||||
#define FT_TOUCH_Y_H 2
|
||||
#define FT_TOUCH_Y_L 3
|
||||
#define FT_TOUCH_EVENT 0
|
||||
#define FT_TOUCH_ID 2
|
||||
|
||||
#define FT_TOUCH_X_H_REG 3
|
||||
#define FT_TOUCH_X_L_REG 4
|
||||
#define FT_TOUCH_Y_H_REG 5
|
||||
#define FT_TOUCH_Y_L_REG 6
|
||||
#define FT_TD_STATUS_REG 2
|
||||
#define FT_TOUCH_EVENT_REG 3
|
||||
#define FT_TOUCH_ID_REG 5
|
||||
|
||||
#define FT_TOUCH_DOWN 0
|
||||
#define FT_TOUCH_CONTACT 2
|
||||
|
||||
struct ts_event {
|
||||
u16 au16_x[MAX_TOUCH_POINTS]; /*x coordinate */
|
||||
u16 au16_y[MAX_TOUCH_POINTS]; /*y coordinate */
|
||||
u8 au8_touch_event[MAX_TOUCH_POINTS]; /*touch event: 0:down; 1:up; 2:contact */
|
||||
u8 au8_finger_id[MAX_TOUCH_POINTS]; /*touch ID */
|
||||
u16 pressure;
|
||||
u8 touch_point;
|
||||
u8 point_num;
|
||||
};
|
||||
|
||||
struct tinker_ft5406_data {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
struct ts_event event;
|
||||
struct work_struct ft5406_work;
|
||||
|
||||
int known_ids;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
232
drivers/miniarm/dsi/tinker_mcu.c
Normal file
232
drivers/miniarm/dsi/tinker_mcu.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
*
|
||||
* Tinker board Touchscreen MCU driver.
|
||||
*
|
||||
* Copyright (c) 2016 ASUSTek Computer Inc.
|
||||
* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include "tinker_mcu.h"
|
||||
|
||||
static struct tinker_mcu_data *g_mcu_data;
|
||||
static int connected = 0;
|
||||
|
||||
static int is_hex(char num)
|
||||
{
|
||||
//0-9, a-f, A-F
|
||||
if ((47 < num && num < 58) || (64 < num && num < 71) || (96 < num && num < 103))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int string_to_byte(const char *source, unsigned char *destination, int size)
|
||||
{
|
||||
int i = 0, counter = 0;
|
||||
char c[3] = {0};
|
||||
unsigned char bytes;
|
||||
|
||||
if (size%2 == 1)
|
||||
return -EINVAL;
|
||||
|
||||
for(i = 0; i < size; i++){
|
||||
if(!is_hex(source[i])) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if(0 == i%2){
|
||||
c[0] = source[i];
|
||||
c[1] = source[i+1];
|
||||
sscanf(c, "%hhx", &bytes);
|
||||
destination[counter] = bytes;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_cmds(struct i2c_client *client, const char *buf)
|
||||
{
|
||||
int ret, size = strlen(buf);
|
||||
unsigned char byte_cmd[size/2];
|
||||
|
||||
if ((size%2) != 0) {
|
||||
LOG_ERR("size should be even\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_INFO("%s\n", buf);
|
||||
|
||||
string_to_byte(buf, byte_cmd, size);
|
||||
|
||||
ret = i2c_master_send(client, byte_cmd, size/2);
|
||||
if (ret <= 0) {
|
||||
LOG_ERR("send command failed, ret = %d\n", ret);
|
||||
return ret!=0 ? ret : -ECOMM;
|
||||
}
|
||||
msleep(20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int recv_cmds(struct i2c_client *client, char *buf, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_master_recv(client, buf, size);
|
||||
if (ret <= 0) {
|
||||
LOG_ERR("receive commands failed, %d\n", ret);
|
||||
return ret!=0 ? ret : -ECOMM;
|
||||
}
|
||||
msleep(20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_cmd_check(struct tinker_mcu_data *mcu_data)
|
||||
{
|
||||
int ret;
|
||||
char recv_buf[1] = {0};
|
||||
|
||||
ret = send_cmds(mcu_data->client, "80");
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
recv_cmds(mcu_data->client, recv_buf, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
LOG_INFO("recv_cmds: 0x%X\n", recv_buf[0]);
|
||||
if (recv_buf[0] != 0xC3) {
|
||||
LOG_ERR("read wrong info\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tinker_mcu_screen_power_up(void)
|
||||
{
|
||||
if (!connected)
|
||||
return -ENODEV;
|
||||
|
||||
LOG_INFO("\n");
|
||||
send_cmds(g_mcu_data->client, "8500");
|
||||
msleep(800);
|
||||
send_cmds(g_mcu_data->client, "8501");
|
||||
send_cmds(g_mcu_data->client, "8104");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tinker_mcu_screen_power_up);
|
||||
|
||||
int tinker_mcu_set_bright(int bright)
|
||||
{
|
||||
unsigned char cmd[2];
|
||||
int ret;
|
||||
|
||||
if (!connected)
|
||||
return -ENODEV;
|
||||
|
||||
if (bright > 0xff || bright < 0)
|
||||
return -EINVAL;
|
||||
|
||||
LOG_INFO("bright = 0x%x\n", bright);
|
||||
|
||||
cmd[0] = 0x86;
|
||||
cmd[1] = bright;
|
||||
|
||||
ret = i2c_master_send(g_mcu_data->client, cmd, 2);
|
||||
if (ret <= 0) {
|
||||
LOG_ERR("send command failed, ret = %d\n", ret);
|
||||
return ret != 0 ? ret : -ECOMM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tinker_mcu_set_bright);
|
||||
|
||||
int tinker_mcu_is_connected(void)
|
||||
{
|
||||
return connected;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tinker_mcu_is_connected);
|
||||
|
||||
static int tinker_mcu_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tinker_mcu_data *mcu_data;
|
||||
int ret;
|
||||
|
||||
LOG_INFO("address = 0x%x\n", client->addr);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
LOG_ERR("I2C check functionality failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mcu_data = kzalloc(sizeof(struct tinker_mcu_data), GFP_KERNEL);
|
||||
if (mcu_data == NULL) {
|
||||
LOG_ERR("no memory for device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mcu_data->client = client;
|
||||
i2c_set_clientdata(client, mcu_data);
|
||||
g_mcu_data = mcu_data;
|
||||
|
||||
ret = init_cmd_check(mcu_data);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("init_cmd_check failed, %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
connected = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(mcu_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tinker_mcu_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tinker_mcu_data *mcu_data = i2c_get_clientdata(client);
|
||||
connected = 0;
|
||||
kfree(mcu_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tinker_mcu_id[] = {
|
||||
{"tinker_mcu", 0},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct i2c_driver tinker_mcu_driver = {
|
||||
.driver = {
|
||||
.name = "tinker_mcu",
|
||||
},
|
||||
.probe = tinker_mcu_probe,
|
||||
.remove = tinker_mcu_remove,
|
||||
.id_table = tinker_mcu_id,
|
||||
};
|
||||
module_i2c_driver(tinker_mcu_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Tinker Board TouchScreen MCU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
14
drivers/miniarm/dsi/tinker_mcu.h
Normal file
14
drivers/miniarm/dsi/tinker_mcu.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _TINKER_MCU_H_
|
||||
#define _TINKER_MCU_H_
|
||||
|
||||
#define LOG_INFO(fmt,arg...) pr_info("tinker-mcu: %s: "fmt, __func__, ##arg);
|
||||
#define LOG_ERR(fmt,arg...) pr_err("tinker-mcu: %s: "fmt, __func__, ##arg);
|
||||
|
||||
#define MAX_I2C_LEN 255
|
||||
|
||||
struct tinker_mcu_data {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -695,6 +695,7 @@ static struct class *spidev_class;
|
||||
static const struct of_device_id spidev_dt_ids[] = {
|
||||
{ .compatible = "rohm,dh2228fv" },
|
||||
{ .compatible = "lineartechnology,ltc2488" },
|
||||
{ .compatible = "rockchip,spi_tinker" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
||||
|
||||
Reference in New Issue
Block a user