1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) 4 * Author: Yong Deng <yong.deng@magewell.com> 5 * Copyright 2021-2022 Bootlin 6 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/err.h> 11 #include <linux/interrupt.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_device.h> 15 #include <linux/platform_device.h> 16 #include <linux/pm_runtime.h> 17 #include <linux/regmap.h> 18 #include <linux/reset.h> 19 #include <media/v4l2-device.h> 20 #include <media/v4l2-mc.h> 21 22 #include "sun6i_csi.h" 23 #include "sun6i_csi_bridge.h" 24 #include "sun6i_csi_capture.h" 25 #include "sun6i_csi_reg.h" 26 27 /* Media */ 28 29 static const struct media_device_ops sun6i_csi_media_ops = { 30 .link_notify = v4l2_pipeline_link_notify, 31 }; 32 33 /* V4L2 */ 34 35 static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) 36 { 37 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 38 struct media_device *media_dev = &v4l2->media_dev; 39 struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; 40 struct device *dev = csi_dev->dev; 41 int ret; 42 43 /* Media Device */ 44 45 strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, 46 sizeof(media_dev->model)); 47 media_dev->hw_revision = 0; 48 media_dev->ops = &sun6i_csi_media_ops; 49 media_dev->dev = dev; 50 51 media_device_init(media_dev); 52 53 ret = media_device_register(media_dev); 54 if (ret) { 55 dev_err(dev, "failed to register media device: %d\n", ret); 56 goto error_media; 57 } 58 59 /* V4L2 Device */ 60 61 v4l2_dev->mdev = media_dev; 62 63 ret = v4l2_device_register(dev, v4l2_dev); 64 if (ret) { 65 dev_err(dev, "failed to register v4l2 device: %d\n", ret); 66 goto error_media; 67 } 68 69 return 0; 70 71 error_media: 72 media_device_unregister(media_dev); 73 media_device_cleanup(media_dev); 74 75 return ret; 76 } 77 78 static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) 79 { 80 struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; 81 82 media_device_unregister(&v4l2->media_dev); 83 v4l2_device_unregister(&v4l2->v4l2_dev); 84 media_device_cleanup(&v4l2->media_dev); 85 } 86 87 /* Platform */ 88 89 static irqreturn_t sun6i_csi_interrupt(int irq, void *private) 90 { 91 struct sun6i_csi_device *csi_dev = private; 92 bool capture_streaming = csi_dev->capture.state.streaming; 93 struct regmap *regmap = csi_dev->regmap; 94 u32 status = 0, enable = 0; 95 96 regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status); 97 regmap_read(regmap, SUN6I_CSI_CH_INT_EN_REG, &enable); 98 99 if (!status) 100 return IRQ_NONE; 101 else if (!(status & enable) || !capture_streaming) 102 goto complete; 103 104 if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) || 105 (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) || 106 (status & SUN6I_CSI_CH_INT_STA_FIFO2_OF) || 107 (status & SUN6I_CSI_CH_INT_STA_HB_OF)) { 108 regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); 109 110 regmap_update_bits(regmap, SUN6I_CSI_EN_REG, 111 SUN6I_CSI_EN_CSI_EN, 0); 112 regmap_update_bits(regmap, SUN6I_CSI_EN_REG, 113 SUN6I_CSI_EN_CSI_EN, SUN6I_CSI_EN_CSI_EN); 114 return IRQ_HANDLED; 115 } 116 117 if (status & SUN6I_CSI_CH_INT_STA_FD) 118 sun6i_csi_capture_frame_done(csi_dev); 119 120 if (status & SUN6I_CSI_CH_INT_STA_VS) 121 sun6i_csi_capture_sync(csi_dev); 122 123 complete: 124 regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); 125 126 return IRQ_HANDLED; 127 } 128 129 static int sun6i_csi_suspend(struct device *dev) 130 { 131 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 132 133 reset_control_assert(csi_dev->reset); 134 clk_disable_unprepare(csi_dev->clock_ram); 135 clk_disable_unprepare(csi_dev->clock_mod); 136 137 return 0; 138 } 139 140 static int sun6i_csi_resume(struct device *dev) 141 { 142 struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); 143 int ret; 144 145 ret = reset_control_deassert(csi_dev->reset); 146 if (ret) { 147 dev_err(dev, "failed to deassert reset\n"); 148 return ret; 149 } 150 151 ret = clk_prepare_enable(csi_dev->clock_mod); 152 if (ret) { 153 dev_err(dev, "failed to enable module clock\n"); 154 goto error_reset; 155 } 156 157 ret = clk_prepare_enable(csi_dev->clock_ram); 158 if (ret) { 159 dev_err(dev, "failed to enable ram clock\n"); 160 goto error_clock_mod; 161 } 162 163 return 0; 164 165 error_clock_mod: 166 clk_disable_unprepare(csi_dev->clock_mod); 167 168 error_reset: 169 reset_control_assert(csi_dev->reset); 170 171 return ret; 172 } 173 174 static const struct dev_pm_ops sun6i_csi_pm_ops = { 175 .runtime_suspend = sun6i_csi_suspend, 176 .runtime_resume = sun6i_csi_resume, 177 }; 178 179 static const struct regmap_config sun6i_csi_regmap_config = { 180 .reg_bits = 32, 181 .reg_stride = 4, 182 .val_bits = 32, 183 .max_register = 0x9c, 184 }; 185 186 static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, 187 struct platform_device *platform_dev) 188 { 189 struct device *dev = csi_dev->dev; 190 const struct sun6i_csi_variant *variant; 191 void __iomem *io_base; 192 int ret; 193 int irq; 194 195 variant = of_device_get_match_data(dev); 196 if (!variant) 197 return -EINVAL; 198 199 /* Registers */ 200 201 io_base = devm_platform_ioremap_resource(platform_dev, 0); 202 if (IS_ERR(io_base)) 203 return PTR_ERR(io_base); 204 205 csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base, 206 &sun6i_csi_regmap_config); 207 if (IS_ERR(csi_dev->regmap)) { 208 dev_err(dev, "failed to init register map\n"); 209 return PTR_ERR(csi_dev->regmap); 210 } 211 212 /* Clocks */ 213 214 csi_dev->clock_mod = devm_clk_get(dev, "mod"); 215 if (IS_ERR(csi_dev->clock_mod)) { 216 dev_err(dev, "failed to acquire module clock\n"); 217 return PTR_ERR(csi_dev->clock_mod); 218 } 219 220 csi_dev->clock_ram = devm_clk_get(dev, "ram"); 221 if (IS_ERR(csi_dev->clock_ram)) { 222 dev_err(dev, "failed to acquire ram clock\n"); 223 return PTR_ERR(csi_dev->clock_ram); 224 } 225 226 ret = clk_set_rate_exclusive(csi_dev->clock_mod, 227 variant->clock_mod_rate); 228 if (ret) { 229 dev_err(dev, "failed to set mod clock rate\n"); 230 return ret; 231 } 232 233 /* Reset */ 234 235 csi_dev->reset = devm_reset_control_get_shared(dev, NULL); 236 if (IS_ERR(csi_dev->reset)) { 237 dev_err(dev, "failed to acquire reset\n"); 238 ret = PTR_ERR(csi_dev->reset); 239 goto error_clock_rate_exclusive; 240 } 241 242 /* Interrupt */ 243 244 irq = platform_get_irq(platform_dev, 0); 245 if (irq < 0) { 246 ret = -ENXIO; 247 goto error_clock_rate_exclusive; 248 } 249 250 ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, 251 csi_dev); 252 if (ret) { 253 dev_err(dev, "failed to request interrupt\n"); 254 goto error_clock_rate_exclusive; 255 } 256 257 /* Runtime PM */ 258 259 pm_runtime_enable(dev); 260 261 return 0; 262 263 error_clock_rate_exclusive: 264 clk_rate_exclusive_put(csi_dev->clock_mod); 265 266 return ret; 267 } 268 269 static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) 270 { 271 pm_runtime_disable(csi_dev->dev); 272 clk_rate_exclusive_put(csi_dev->clock_mod); 273 } 274 275 static int sun6i_csi_probe(struct platform_device *platform_dev) 276 { 277 struct sun6i_csi_device *csi_dev; 278 struct device *dev = &platform_dev->dev; 279 int ret; 280 281 csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL); 282 if (!csi_dev) 283 return -ENOMEM; 284 285 csi_dev->dev = &platform_dev->dev; 286 platform_set_drvdata(platform_dev, csi_dev); 287 288 ret = sun6i_csi_resources_setup(csi_dev, platform_dev); 289 if (ret) 290 return ret; 291 292 ret = sun6i_csi_v4l2_setup(csi_dev); 293 if (ret) 294 goto error_resources; 295 296 ret = sun6i_csi_bridge_setup(csi_dev); 297 if (ret) 298 goto error_v4l2; 299 300 ret = sun6i_csi_capture_setup(csi_dev); 301 if (ret) 302 goto error_bridge; 303 304 return 0; 305 306 error_bridge: 307 sun6i_csi_bridge_cleanup(csi_dev); 308 309 error_v4l2: 310 sun6i_csi_v4l2_cleanup(csi_dev); 311 312 error_resources: 313 sun6i_csi_resources_cleanup(csi_dev); 314 315 return ret; 316 } 317 318 static int sun6i_csi_remove(struct platform_device *pdev) 319 { 320 struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); 321 322 sun6i_csi_capture_cleanup(csi_dev); 323 sun6i_csi_bridge_cleanup(csi_dev); 324 sun6i_csi_v4l2_cleanup(csi_dev); 325 sun6i_csi_resources_cleanup(csi_dev); 326 327 return 0; 328 } 329 330 static const struct sun6i_csi_variant sun6i_a31_csi_variant = { 331 .clock_mod_rate = 297000000, 332 }; 333 334 static const struct sun6i_csi_variant sun50i_a64_csi_variant = { 335 .clock_mod_rate = 300000000, 336 }; 337 338 static const struct of_device_id sun6i_csi_of_match[] = { 339 { 340 .compatible = "allwinner,sun6i-a31-csi", 341 .data = &sun6i_a31_csi_variant, 342 }, 343 { 344 .compatible = "allwinner,sun8i-a83t-csi", 345 .data = &sun6i_a31_csi_variant, 346 }, 347 { 348 .compatible = "allwinner,sun8i-h3-csi", 349 .data = &sun6i_a31_csi_variant, 350 }, 351 { 352 .compatible = "allwinner,sun8i-v3s-csi", 353 .data = &sun6i_a31_csi_variant, 354 }, 355 { 356 .compatible = "allwinner,sun50i-a64-csi", 357 .data = &sun50i_a64_csi_variant, 358 }, 359 {}, 360 }; 361 362 MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); 363 364 static struct platform_driver sun6i_csi_platform_driver = { 365 .probe = sun6i_csi_probe, 366 .remove = sun6i_csi_remove, 367 .driver = { 368 .name = SUN6I_CSI_NAME, 369 .of_match_table = of_match_ptr(sun6i_csi_of_match), 370 .pm = &sun6i_csi_pm_ops, 371 }, 372 }; 373 374 module_platform_driver(sun6i_csi_platform_driver); 375 376 MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); 377 MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>"); 378 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 379 MODULE_LICENSE("GPL"); 380