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; 35static struct clk *camio_vfe_axi_clk; 36static struct msm_camera_io_ext camio_ext; 37static struct resource *appio, *mdcio; 38void __iomem *appbase, *mdcbase; 39 40extern int clk_set_flags(struct clk *clk, unsigned long flags); 41 42int msm_camio_clk_enable(enum msm_camio_clk_type clktype) 43{ 44 int rc = 0; 45 struct clk *clk = NULL; 46 47 switch (clktype) { 48 case CAMIO_VFE_MDC_CLK: 49 camio_vfe_mdc_clk = 50 clk = clk_get(NULL, "vfe_mdc_clk"); 51 break; 52 53 case CAMIO_MDC_CLK: 54 camio_mdc_clk = 55 clk = clk_get(NULL, "mdc_clk"); 56 break; 57 58 case CAMIO_VFE_CLK: 59 camio_vfe_clk = 60 clk = clk_get(NULL, "vfe_clk"); 61 break; 62 63 case CAMIO_VFE_AXI_CLK: 64 camio_vfe_axi_clk = 65 clk = clk_get(NULL, "vfe_axi_clk"); 66 break; 67 68 default: 69 break; 70 } 71 72 if (!IS_ERR(clk)) 73 clk_enable(clk); 74 else 75 rc = -1; 76 77 return rc; 78} 79 80int msm_camio_clk_disable(enum msm_camio_clk_type clktype) 81{ 82 int rc = 0; 83 struct clk *clk = NULL; 84 85 switch (clktype) { 86 case CAMIO_VFE_MDC_CLK: 87 clk = camio_vfe_mdc_clk; 88 break; 89 90 case CAMIO_MDC_CLK: 91 clk = camio_mdc_clk; 92 break; 93 94 case CAMIO_VFE_CLK: 95 clk = camio_vfe_clk; 96 break; 97 98 case CAMIO_VFE_AXI_CLK: 99 clk = camio_vfe_axi_clk; 100 break; 101 102 default: 103 break; 104 } 105 106 if (!IS_ERR(clk)) { 107 clk_disable(clk); 108 clk_put(clk); 109 } else 110 rc = -1; 111 112 return rc; 113} 114 115void msm_camio_clk_rate_set(int rate) 116{ 117 struct clk *clk = camio_vfe_mdc_clk; 118 119 /* TODO: check return */ 120 clk_set_rate(clk, rate); 121} 122 123int msm_camio_enable(struct platform_device *pdev) 124{ 125 int rc = 0; 126 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 127 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 128 129 camio_ext = camdev->ioext; 130 131 appio = request_mem_region(camio_ext.appphy, 132 camio_ext.appsz, pdev->name); 133 if (!appio) { 134 rc = -EBUSY; 135 goto enable_fail; 136 } 137 138 appbase = ioremap(camio_ext.appphy, 139 camio_ext.appsz); 140 if (!appbase) { 141 rc = -ENOMEM; 142 goto apps_no_mem; 143 } 144 145 mdcio = request_mem_region(camio_ext.mdcphy, 146 camio_ext.mdcsz, pdev->name); 147 if (!mdcio) { 148 rc = -EBUSY; 149 goto mdc_busy; 150 } 151 152 mdcbase = ioremap(camio_ext.mdcphy, 153 camio_ext.mdcsz); 154 if (!mdcbase) { 155 rc = -ENOMEM; 156 goto mdc_no_mem; 157 } 158 159 camdev->camera_gpio_on(); 160 161 msm_camio_clk_enable(CAMIO_VFE_CLK); 162 msm_camio_clk_enable(CAMIO_MDC_CLK); 163 msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); 164 msm_camio_clk_enable(CAMIO_VFE_AXI_CLK); 165 return 0; 166 167mdc_no_mem: 168 release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); 169mdc_busy: 170 iounmap(appbase); 171apps_no_mem: 172 release_mem_region(camio_ext.appphy, camio_ext.appsz); 173enable_fail: 174 return rc; 175} 176 177void msm_camio_disable(struct platform_device *pdev) 178{ 179 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 180 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 181 182 iounmap(mdcbase); 183 release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz); 184 iounmap(appbase); 185 release_mem_region(camio_ext.appphy, camio_ext.appsz); 186 187 camdev->camera_gpio_off(); 188 189 msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); 190 msm_camio_clk_disable(CAMIO_MDC_CLK); 191 msm_camio_clk_disable(CAMIO_VFE_CLK); 192 msm_camio_clk_disable(CAMIO_VFE_AXI_CLK); 193} 194 195void msm_camio_camif_pad_reg_reset(void) 196{ 197 uint32_t reg; 198 uint32_t mask, value; 199 200 /* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */ 201 msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL); 202 203 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 204 205 mask = CAM_SEL_BMSK | 206 CAM_PCLK_SRC_SEL_BMSK | 207 CAM_PCLK_INVERT_BMSK | 208 EXT_CAM_HSYNC_POL_SEL_BMSK | 209 EXT_CAM_VSYNC_POL_SEL_BMSK | 210 MDDI_CLK_CHICKEN_BIT_BMSK; 211 212 value = 1 << CAM_SEL_SHFT | 213 3 << CAM_PCLK_SRC_SEL_SHFT | 214 0 << CAM_PCLK_INVERT_SHFT | 215 0 << EXT_CAM_HSYNC_POL_SEL_SHFT | 216 0 << EXT_CAM_VSYNC_POL_SEL_SHFT | 217 0 << MDDI_CLK_CHICKEN_BIT_SHFT; 218 writel((reg & (~mask)) | (value & mask), mdcbase); 219 mdelay(10); 220 221 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 222 mask = CAM_PAD_REG_SW_RESET_BMSK; 223 value = 1 << CAM_PAD_REG_SW_RESET_SHFT; 224 writel((reg & (~mask)) | (value & mask), mdcbase); 225 mdelay(10); 226 227 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 228 mask = CAM_PAD_REG_SW_RESET_BMSK; 229 value = 0 << CAM_PAD_REG_SW_RESET_SHFT; 230 writel((reg & (~mask)) | (value & mask), mdcbase); 231 mdelay(10); 232 233 msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL); 234 235 mdelay(10); 236 237 /* todo: check return */ 238 if (camio_vfe_clk) 239 clk_set_rate(camio_vfe_clk, 96000000); 240} 241 242void msm_camio_vfe_blk_reset(void) 243{ 244 uint32_t val; 245 246 val = readl(appbase + 0x00000210); 247 val |= 0x1; 248 writel(val, appbase + 0x00000210); 249 mdelay(10); 250 251 val = readl(appbase + 0x00000210); 252 val &= ~0x1; 253 writel(val, appbase + 0x00000210); 254 mdelay(10); 255} 256 257void msm_camio_camif_pad_reg_reset_2(void) 258{ 259 uint32_t reg; 260 uint32_t mask, value; 261 262 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 263 mask = CAM_PAD_REG_SW_RESET_BMSK; 264 value = 1 << CAM_PAD_REG_SW_RESET_SHFT; 265 writel((reg & (~mask)) | (value & mask), mdcbase); 266 mdelay(10); 267 268 reg = (readl(mdcbase)) & CAMIF_CFG_RMSK; 269 mask = CAM_PAD_REG_SW_RESET_BMSK; 270 value = 0 << CAM_PAD_REG_SW_RESET_SHFT; 271 writel((reg & (~mask)) | (value & mask), mdcbase); 272 mdelay(10); 273} 274 275void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype) 276{ 277 struct clk *clk = NULL; 278 279 clk = camio_vfe_clk; 280 281 if (clk != NULL) { 282 switch (srctype) { 283 case MSM_CAMIO_CLK_SRC_INTERNAL: 284 clk_set_flags(clk, 0x00000100 << 1); 285 break; 286 287 case MSM_CAMIO_CLK_SRC_EXTERNAL: 288 clk_set_flags(clk, 0x00000100); 289 break; 290 291 default: 292 break; 293 } 294 } 295} 296 297void msm_camio_clk_axi_rate_set(int rate) 298{ 299 struct clk *clk = camio_vfe_axi_clk; 300 /* todo: check return */ 301 clk_set_rate(clk, rate); 302} 303 304int msm_camio_probe_on(struct platform_device *pdev) 305{ 306 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 307 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 308 309 camdev->camera_gpio_on(); 310 return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK); 311} 312 313int msm_camio_probe_off(struct platform_device *pdev) 314{ 315 struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data; 316 struct msm_camera_device_platform_data *camdev = sinfo->pdata; 317 318 camdev->camera_gpio_off(); 319 return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK); 320} 321