aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5pv210/setup-fimc0.c
blob: c48c14910f9e1872374dcb294a6034de2ad5f6a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* linux/arch/arm/mach-s5pv210/setup-fimc0.c
 *
 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
 *		http://www.samsung.com/
 *
 * Base FIMC 0 gpio configuration
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
*/

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <plat/clock.h>
#include <plat/gpio-cfg.h>
#include <plat/map-s5p.h>
#include <mach/regs-gpio.h>
#include <mach/map.h>
#include <mach/pd.h>
#include <plat/regs-fimc.h>

struct platform_device; /* don't need the contents */

void s3c_fimc0_cfg_gpio(struct platform_device *pdev)
{
	int i = 0;

	/* CAM A port(b0010) : PCLK, VSYNC, HREF, DATA[0-4] */
	for (i = 0; i < 8; i++) {
		s3c_gpio_cfgpin(S5PV210_GPE0(i), S3C_GPIO_SFN(2));
		s3c_gpio_setpull(S5PV210_GPE0(i), S3C_GPIO_PULL_NONE);
	}
	/* CAM A port(b0010) : DATA[5-7], CLKOUT(MIPI CAM also), FIELD */
	for (i = 0; i < 4; i++) {
		s3c_gpio_cfgpin(S5PV210_GPE1(i), S3C_GPIO_SFN(2));
		s3c_gpio_setpull(S5PV210_GPE1(i), S3C_GPIO_PULL_NONE);
	}

#if defined(CONFIG_MACH_SMDKC110) || defined(CONFIG_MACH_SMDKV210)
	s3c_gpio_cfgpin(S5PV210_GPE1(4), S5PV210_GPE1_4_CAM_A_FIELD);
	s3c_gpio_setpull(S5PV210_GPE1(4), S3C_GPIO_PULL_NONE);

	/* CAM B port(b0011) : DATA[0-7] */
	for (i = 0; i < 8; i++) {
		s3c_gpio_cfgpin(S5PV210_GPJ0(i), S3C_GPIO_SFN(3));
		s3c_gpio_setpull(S5PV210_GPJ0(i), S3C_GPIO_PULL_NONE);
	}
	/* CAM B port(b0011) : PCLK, VSYNC, HREF, FIELD, CLCKOUT */
	for (i = 0; i < 5; i++) {
		s3c_gpio_cfgpin(S5PV210_GPJ1(i), S3C_GPIO_SFN(3));
		s3c_gpio_setpull(S5PV210_GPJ1(i), S3C_GPIO_PULL_NONE);
	}
#endif

	/* note : driver strength to max is unnecessary */
}

int s3c_fimc_clk_on(struct platform_device *pdev, struct clk *clk)
{
	struct clk *sclk_fimc_lclk = NULL;
	struct clk *mout_fimc_lclk = NULL;
	struct clk *mout_mpll = NULL;
	int ret;

	mout_mpll = clk_get(&pdev->dev, "mout_mpll");
	if (IS_ERR(mout_mpll)) {
		dev_err(&pdev->dev, "failed to get mout_mpll\n");
		goto err_clk1;
	}

	mout_fimc_lclk = clk_get(&pdev->dev, "mout_fimc_lclk");
	if (IS_ERR(mout_fimc_lclk)) {
		dev_err(&pdev->dev, "failed to get mout_fimc_lclk\n");
		goto err_clk2;
	}

	sclk_fimc_lclk = clk_get(&pdev->dev, "fimc");
	if (IS_ERR(sclk_fimc_lclk)) {
		dev_err(&pdev->dev, "failed to get sclk_fimc_lclk\n");
		goto err_clk3;
	}

	clk_set_parent(mout_fimc_lclk, mout_mpll);
	clk_set_rate(sclk_fimc_lclk, 166750000);

	/* be able to handle clock on/off only with this clock */
	clk = clk_get(&pdev->dev, "fimc");
	if (IS_ERR(clk)) {
		dev_err(&pdev->dev, "failed to get interface clock\n");
		goto err_clk3;
	}

	clk_put(mout_mpll);
	clk_put(mout_fimc_lclk);

	ret = s5pv210_pd_enable("fimc_pd");
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to enable fimc power domain\n");
		goto err_clk3;
	}

	clk_enable(clk);

	return 0;

err_clk3:
	clk_put(mout_fimc_lclk);

err_clk2:
	clk_put(mout_mpll);

err_clk1:
	return -EINVAL;
}

int s3c_fimc_clk_off(struct platform_device *pdev, struct clk *clk)
{
	int ret;

	clk_disable(clk);
	clk_put(clk);

	clk = NULL;
	ret = s5pv210_pd_disable("fimc_pd");
	if (ret < 0)
		dev_err(&pdev->dev, "failed to disable fimc power domain\n");

	return 0;
}