1/* 2 * Copyright (c) 2008-2009 QUALCOMM Incorporated 3 */ 4 5#include <linux/delay.h> 6#include <linux/clk.h> 7#include <linux/io.h> 8#include <mach/gpio.h> 9#include <mach/board.h> 10#include <mach/camera.h> 11 12#define CAMIF_CFG_RMSK 0x1fffff 13#define CAM_SEL_BMSK 0x2 14#define CAM_PCLK_SRC_SEL_BMSK 0x60000 15#define CAM_PCLK_INVERT_BMSK 0x80000 16#define CAM_PAD_REG_SW_RESET_BMSK 0x100000 17 18#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000 19#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000 20#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80 21 22#define CAM_SEL_SHFT 0x1 23#define CAM_PCLK_SRC_SEL_SHFT 0x11 24#define CAM_PCLK_INVERT_SHFT 0x13 25#define CAM_PAD_REG_SW_RESET_SHFT 0x14 26 27#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10 28#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF 29#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7 30#define APPS_RESET_OFFSET 0x00000210 31 32static struct clk *camio_vfe_mdc_clk; 33static struct clk *camio_mdc_clk; 34static struct clk *camio_vfe_clk; 35 36static struct msm_camera_io_ext camio_ext; 37static struct resource *appio, *mdcio; 38void __iomem *appbase, *mdcbase; 39 40static struct msm_camera_io_ext camio_ext; 41static struct resource *appio, *mdcio; 42void __iomem *appbase, *mdcbase; 43 44extern int clk_set_flags(struct clk *clk, unsigned long flags); 45 46int msm_camio_clk_enable(enum msm_camio_clk_type clktype) 47{ 48 int rc = -1; 49 struct clk *clk = NULL; 50 51 switch (clktype) { 52 case CAMIO_VFE_MDC_CLK: 53 clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk"); 54 break; 55 56 case CAMIO_MDC_CLK: 57 clk = camio_mdc_clk = clk_get(NULL, "mdc_clk"); 58 break; 59 60 case CAMIO_VFE_CLK: 61 clk = camio_vfe_clk = clk_get(NULL, "vfe_clk"); 62 break; 63 64 default: 65 break; 66 } 67 68 if (!IS_ERR(clk)) { 69 clk_enable(clk); 70 rc = 0; 71 } 72 73 return rc; 74} 75 76int msm_camio_clk_disable(enum msm_camio_clk_type clktype) 77{ 78 int rc = -1; 79 struct clk *clk = NULL; 80 81 switch (clktype) { 82 case CAMIO_VFE_MDC_CLK: 83 clk = camio_vfe_mdc_clk; 84 break; 85 86 case CAMIO_MDC_CLK: 87 clk = camio_mdc_clk; 88 break; 89 90 case CAMIO_VFE_CLK: 91 clk = camio_vfe_clk; 92 break; 93 94 default: 95 break; 96 } 97 98 if (!IS_ERR(clk)) { 99 clk_disable(clk); 100 clk_put(clk); 101 rc = 0; 102 } 103 104 return rc; 105} 106 107void msm_camio_clk_rate_set(int rate) 108{ 109 struct clk *clk = camio_vfe_clk; 110 111 if (clk != ERR_PTR(-ENOENT)) 112 clk_set_rate(clk, rate); 113} 114 115int msm_camio_enable(struct platform_device *pdev) 116{ 117 int rc = 0; 118 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 119 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 120 121 camio_ext = camdev->ioext; 122 123 appio = request_mem_region(camio_ext.appphy, 124 camio_ext.appsz, pdev->name); 125 if (!appio) { 126 rc = -EBUSY; 127 goto enable_fail; 128 } 129 130 appbase = ioremap(camio_ext.appphy, 131 camio_ext.appsz); 132 if (!appbase) { 133 rc = -ENOMEM; 134 goto apps_no_mem; 135 } 136 137 mdcio = request_mem_region(camio_ext.mdcphy, 138 camio_ext.mdcsz, pdev->name); 139 if (!mdcio) { 140 rc = -EBUSY; 141 goto mdc_busy; 142 } 143 144 mdcbase = ioremap(camio_ext.mdcphy, 145 camio_ext.mdcsz); 146 if (!mdcbase) { 147 rc = -ENOMEM; 148 goto mdc_no_mem; 149 } 150 151 camdev->camera_gpio_on(); 152 153 msm_camio_clk_enable(CAMIO_VFE_CLK); 154 msm_camio_clk_enable(CAMIO_MDC_CLK); 155 msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); 156 return 0; 157 158mdc_no_mem: 159 release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); 160mdc_busy: 161 iounmap(appbase); 162apps_no_mem: 163 release_mem_region(camio_ext.appphy, camio_ext.appsz); 164enable_fail: 165 return rc; 166} 167 168void msm_camio_disable(struct platform_device *pdev) 169{ 170 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 171 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 172 173 iounmap(mdcbase); 174 release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); 175 iounmap(appbase); 176 release_mem_region(camio_ext.appphy, camio_ext.appsz); 177 178 camdev->camera_gpio_off(); 179 180 msm_camio_clk_disable(CAMIO_VFE_CLK); 181 msm_camio_clk_disable(CAMIO_MDC_CLK); 182 msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); 183} 184 185void msm_camio_camif_pad_reg_reset(void) 186{ 187 uint32_t reg; 188 uint32_t mask, value; 189 190 /* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */ 191 msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL); 192 193 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 194 195 mask = CAM_SEL_BMSK | 196 CAM_PCLK_SRC_SEL_BMSK | 197 CAM_PCLK_INVERT_BMSK; 198 199 value = 1 << CAM_SEL_SHFT | 200 3 << CAM_PCLK_SRC_SEL_SHFT | 201 0 << CAM_PCLK_INVERT_SHFT; 202 203 writel((reg & (~mask)) | (value & mask), mdcbase); 204 mdelay(10); 205 206 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 207 mask = CAM_PAD_REG_SW_RESET_BMSK; 208 value = 1 << CAM_PAD_REG_SW_RESET_SHFT; 209 writel((reg & (~mask)) | (value & mask), mdcbase); 210 mdelay(10); 211 212 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 213 mask = CAM_PAD_REG_SW_RESET_BMSK; 214 value = 0 << CAM_PAD_REG_SW_RESET_SHFT; 215 writel((reg & (~mask)) | (value & mask), mdcbase); 216 mdelay(10); 217 218 msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL); 219 mdelay(10); 220} 221 222void msm_camio_vfe_blk_reset(void) 223{ 224 uint32_t val; 225 226 val = readl(appbase + 0x00000210); 227 val |= 0x1; 228 writel(val, appbase + 0x00000210); 229 mdelay(10); 230 231 val = readl(appbase + 0x00000210); 232 val &= ~0x1; 233 writel(val, appbase + 0x00000210); 234 mdelay(10); 235} 236 237void msm_camio_camif_pad_reg_reset_2(void) 238{ 239 uint32_t reg; 240 uint32_t mask, value; 241 242 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 243 mask = CAM_PAD_REG_SW_RESET_BMSK; 244 value = 1 << CAM_PAD_REG_SW_RESET_SHFT; 245 writel((reg & (~mask)) | (value & mask), mdcbase); 246 mdelay(10); 247 248 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 249 mask = CAM_PAD_REG_SW_RESET_BMSK; 250 value = 0 << CAM_PAD_REG_SW_RESET_SHFT; 251 writel((reg & (~mask)) | (value & mask), mdcbase); 252 mdelay(10); 253} 254 255void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype) 256{ 257 struct clk *clk = NULL; 258 259 clk = camio_vfe_clk; 260 261 if (clk != NULL && clk != ERR_PTR(-ENOENT)) { 262 switch (srctype) { 263 case MSM_CAMIO_CLK_SRC_INTERNAL: 264 clk_set_flags(clk, 0x00000100 << 1); 265 break; 266 267 case MSM_CAMIO_CLK_SRC_EXTERNAL: 268 clk_set_flags(clk, 0x00000100); 269 break; 270 271 default: 272 break; 273 } 274 } 275} 276 277int msm_camio_probe_on(struct platform_device *pdev) 278{ 279 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 280 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 281 camdev->camera_gpio_on(); 282 return msm_camio_clk_enable(CAMIO_VFE_CLK); 283} 284 285int msm_camio_probe_off(struct platform_device *pdev) 286{ 287 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 288 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 289 camdev->camera_gpio_off(); 290 return msm_camio_clk_disable(CAMIO_VFE_CLK); 291} 292