1*f2cb3148SBenjamin Gaignard /* 2*f2cb3148SBenjamin Gaignard * Copyright (C) STMicroelectronics SA 2014 3*f2cb3148SBenjamin Gaignard * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4*f2cb3148SBenjamin Gaignard * Fabien Dessenne <fabien.dessenne@st.com> 5*f2cb3148SBenjamin Gaignard * Vincent Abriou <vincent.abriou@st.com> 6*f2cb3148SBenjamin Gaignard * for STMicroelectronics. 7*f2cb3148SBenjamin Gaignard * License terms: GNU General Public License (GPL), version 2 8*f2cb3148SBenjamin Gaignard */ 9*f2cb3148SBenjamin Gaignard 10*f2cb3148SBenjamin Gaignard #include <linux/module.h> 11*f2cb3148SBenjamin Gaignard #include <linux/notifier.h> 12*f2cb3148SBenjamin Gaignard #include <linux/platform_device.h> 13*f2cb3148SBenjamin Gaignard 14*f2cb3148SBenjamin Gaignard #include <drm/drmP.h> 15*f2cb3148SBenjamin Gaignard 16*f2cb3148SBenjamin Gaignard #include "sti_vtg.h" 17*f2cb3148SBenjamin Gaignard 18*f2cb3148SBenjamin Gaignard #define VTG_TYPE_MASTER 0 19*f2cb3148SBenjamin Gaignard #define VTG_TYPE_SLAVE_BY_EXT0 1 20*f2cb3148SBenjamin Gaignard 21*f2cb3148SBenjamin Gaignard /* registers offset */ 22*f2cb3148SBenjamin Gaignard #define VTG_MODE 0x0000 23*f2cb3148SBenjamin Gaignard #define VTG_CLKLN 0x0008 24*f2cb3148SBenjamin Gaignard #define VTG_HLFLN 0x000C 25*f2cb3148SBenjamin Gaignard #define VTG_DRST_AUTOC 0x0010 26*f2cb3148SBenjamin Gaignard #define VTG_VID_TFO 0x0040 27*f2cb3148SBenjamin Gaignard #define VTG_VID_TFS 0x0044 28*f2cb3148SBenjamin Gaignard #define VTG_VID_BFO 0x0048 29*f2cb3148SBenjamin Gaignard #define VTG_VID_BFS 0x004C 30*f2cb3148SBenjamin Gaignard 31*f2cb3148SBenjamin Gaignard #define VTG_HOST_ITS 0x0078 32*f2cb3148SBenjamin Gaignard #define VTG_HOST_ITS_BCLR 0x007C 33*f2cb3148SBenjamin Gaignard #define VTG_HOST_ITM_BCLR 0x0088 34*f2cb3148SBenjamin Gaignard #define VTG_HOST_ITM_BSET 0x008C 35*f2cb3148SBenjamin Gaignard 36*f2cb3148SBenjamin Gaignard #define VTG_H_HD_1 0x00C0 37*f2cb3148SBenjamin Gaignard #define VTG_TOP_V_VD_1 0x00C4 38*f2cb3148SBenjamin Gaignard #define VTG_BOT_V_VD_1 0x00C8 39*f2cb3148SBenjamin Gaignard #define VTG_TOP_V_HD_1 0x00CC 40*f2cb3148SBenjamin Gaignard #define VTG_BOT_V_HD_1 0x00D0 41*f2cb3148SBenjamin Gaignard 42*f2cb3148SBenjamin Gaignard #define VTG_H_HD_2 0x00E0 43*f2cb3148SBenjamin Gaignard #define VTG_TOP_V_VD_2 0x00E4 44*f2cb3148SBenjamin Gaignard #define VTG_BOT_V_VD_2 0x00E8 45*f2cb3148SBenjamin Gaignard #define VTG_TOP_V_HD_2 0x00EC 46*f2cb3148SBenjamin Gaignard #define VTG_BOT_V_HD_2 0x00F0 47*f2cb3148SBenjamin Gaignard 48*f2cb3148SBenjamin Gaignard #define VTG_H_HD_3 0x0100 49*f2cb3148SBenjamin Gaignard #define VTG_TOP_V_VD_3 0x0104 50*f2cb3148SBenjamin Gaignard #define VTG_BOT_V_VD_3 0x0108 51*f2cb3148SBenjamin Gaignard #define VTG_TOP_V_HD_3 0x010C 52*f2cb3148SBenjamin Gaignard #define VTG_BOT_V_HD_3 0x0110 53*f2cb3148SBenjamin Gaignard 54*f2cb3148SBenjamin Gaignard #define VTG_IRQ_BOTTOM BIT(0) 55*f2cb3148SBenjamin Gaignard #define VTG_IRQ_TOP BIT(1) 56*f2cb3148SBenjamin Gaignard #define VTG_IRQ_MASK (VTG_IRQ_TOP | VTG_IRQ_BOTTOM) 57*f2cb3148SBenjamin Gaignard 58*f2cb3148SBenjamin Gaignard /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ 59*f2cb3148SBenjamin Gaignard #define AWG_DELAY_HD (-9) 60*f2cb3148SBenjamin Gaignard #define AWG_DELAY_ED (-8) 61*f2cb3148SBenjamin Gaignard #define AWG_DELAY_SD (-7) 62*f2cb3148SBenjamin Gaignard 63*f2cb3148SBenjamin Gaignard LIST_HEAD(vtg_lookup); 64*f2cb3148SBenjamin Gaignard 65*f2cb3148SBenjamin Gaignard /** 66*f2cb3148SBenjamin Gaignard * STI VTG structure 67*f2cb3148SBenjamin Gaignard * 68*f2cb3148SBenjamin Gaignard * @dev: pointer to device driver 69*f2cb3148SBenjamin Gaignard * @data: data associated to the device 70*f2cb3148SBenjamin Gaignard * @irq: VTG irq 71*f2cb3148SBenjamin Gaignard * @type: VTG type (main or aux) 72*f2cb3148SBenjamin Gaignard * @notifier_list: notifier callback 73*f2cb3148SBenjamin Gaignard * @crtc_id: the crtc id for vblank event 74*f2cb3148SBenjamin Gaignard * @slave: slave vtg 75*f2cb3148SBenjamin Gaignard * @link: List node to link the structure in lookup list 76*f2cb3148SBenjamin Gaignard */ 77*f2cb3148SBenjamin Gaignard struct sti_vtg { 78*f2cb3148SBenjamin Gaignard struct device *dev; 79*f2cb3148SBenjamin Gaignard struct device_node *np; 80*f2cb3148SBenjamin Gaignard void __iomem *regs; 81*f2cb3148SBenjamin Gaignard int irq; 82*f2cb3148SBenjamin Gaignard u32 irq_status; 83*f2cb3148SBenjamin Gaignard struct raw_notifier_head notifier_list; 84*f2cb3148SBenjamin Gaignard int crtc_id; 85*f2cb3148SBenjamin Gaignard struct sti_vtg *slave; 86*f2cb3148SBenjamin Gaignard struct list_head link; 87*f2cb3148SBenjamin Gaignard }; 88*f2cb3148SBenjamin Gaignard 89*f2cb3148SBenjamin Gaignard static void vtg_register(struct sti_vtg *vtg) 90*f2cb3148SBenjamin Gaignard { 91*f2cb3148SBenjamin Gaignard list_add_tail(&vtg->link, &vtg_lookup); 92*f2cb3148SBenjamin Gaignard } 93*f2cb3148SBenjamin Gaignard 94*f2cb3148SBenjamin Gaignard struct sti_vtg *of_vtg_find(struct device_node *np) 95*f2cb3148SBenjamin Gaignard { 96*f2cb3148SBenjamin Gaignard struct sti_vtg *vtg; 97*f2cb3148SBenjamin Gaignard 98*f2cb3148SBenjamin Gaignard list_for_each_entry(vtg, &vtg_lookup, link) { 99*f2cb3148SBenjamin Gaignard if (vtg->np == np) 100*f2cb3148SBenjamin Gaignard return vtg; 101*f2cb3148SBenjamin Gaignard } 102*f2cb3148SBenjamin Gaignard return NULL; 103*f2cb3148SBenjamin Gaignard } 104*f2cb3148SBenjamin Gaignard EXPORT_SYMBOL(of_vtg_find); 105*f2cb3148SBenjamin Gaignard 106*f2cb3148SBenjamin Gaignard static void vtg_reset(struct sti_vtg *vtg) 107*f2cb3148SBenjamin Gaignard { 108*f2cb3148SBenjamin Gaignard /* reset slave and then master */ 109*f2cb3148SBenjamin Gaignard if (vtg->slave) 110*f2cb3148SBenjamin Gaignard vtg_reset(vtg->slave); 111*f2cb3148SBenjamin Gaignard 112*f2cb3148SBenjamin Gaignard writel(1, vtg->regs + VTG_DRST_AUTOC); 113*f2cb3148SBenjamin Gaignard } 114*f2cb3148SBenjamin Gaignard 115*f2cb3148SBenjamin Gaignard static void vtg_set_mode(struct sti_vtg *vtg, 116*f2cb3148SBenjamin Gaignard int type, const struct drm_display_mode *mode) 117*f2cb3148SBenjamin Gaignard { 118*f2cb3148SBenjamin Gaignard u32 tmp; 119*f2cb3148SBenjamin Gaignard 120*f2cb3148SBenjamin Gaignard if (vtg->slave) 121*f2cb3148SBenjamin Gaignard vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode); 122*f2cb3148SBenjamin Gaignard 123*f2cb3148SBenjamin Gaignard writel(mode->htotal, vtg->regs + VTG_CLKLN); 124*f2cb3148SBenjamin Gaignard writel(mode->vtotal * 2, vtg->regs + VTG_HLFLN); 125*f2cb3148SBenjamin Gaignard 126*f2cb3148SBenjamin Gaignard tmp = (mode->vtotal - mode->vsync_start + 1) << 16; 127*f2cb3148SBenjamin Gaignard tmp |= mode->htotal - mode->hsync_start; 128*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_VID_TFO); 129*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_VID_BFO); 130*f2cb3148SBenjamin Gaignard 131*f2cb3148SBenjamin Gaignard tmp = (mode->vdisplay + mode->vtotal - mode->vsync_start + 1) << 16; 132*f2cb3148SBenjamin Gaignard tmp |= mode->hdisplay + mode->htotal - mode->hsync_start; 133*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_VID_TFS); 134*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_VID_BFS); 135*f2cb3148SBenjamin Gaignard 136*f2cb3148SBenjamin Gaignard /* prepare VTG set 1 and 2 for HDMI and VTG set 3 for HD DAC */ 137*f2cb3148SBenjamin Gaignard tmp = (mode->hsync_end - mode->hsync_start) << 16; 138*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_H_HD_1); 139*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_H_HD_2); 140*f2cb3148SBenjamin Gaignard 141*f2cb3148SBenjamin Gaignard tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 142*f2cb3148SBenjamin Gaignard tmp |= 1; 143*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_TOP_V_VD_1); 144*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_BOT_V_VD_1); 145*f2cb3148SBenjamin Gaignard writel(0, vtg->regs + VTG_TOP_V_HD_1); 146*f2cb3148SBenjamin Gaignard writel(0, vtg->regs + VTG_BOT_V_HD_1); 147*f2cb3148SBenjamin Gaignard 148*f2cb3148SBenjamin Gaignard /* prepare VTG set 2 for for HD DCS */ 149*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_TOP_V_VD_2); 150*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_BOT_V_VD_2); 151*f2cb3148SBenjamin Gaignard writel(0, vtg->regs + VTG_TOP_V_HD_2); 152*f2cb3148SBenjamin Gaignard writel(0, vtg->regs + VTG_BOT_V_HD_2); 153*f2cb3148SBenjamin Gaignard 154*f2cb3148SBenjamin Gaignard /* prepare VTG set 3 for HD Analog in HD mode */ 155*f2cb3148SBenjamin Gaignard tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16; 156*f2cb3148SBenjamin Gaignard tmp |= mode->htotal + AWG_DELAY_HD; 157*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_H_HD_3); 158*f2cb3148SBenjamin Gaignard 159*f2cb3148SBenjamin Gaignard tmp = (mode->vsync_end - mode->vsync_start) << 16; 160*f2cb3148SBenjamin Gaignard tmp |= mode->vtotal; 161*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_TOP_V_VD_3); 162*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_BOT_V_VD_3); 163*f2cb3148SBenjamin Gaignard 164*f2cb3148SBenjamin Gaignard tmp = (mode->htotal + AWG_DELAY_HD) << 16; 165*f2cb3148SBenjamin Gaignard tmp |= mode->htotal + AWG_DELAY_HD; 166*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_TOP_V_HD_3); 167*f2cb3148SBenjamin Gaignard writel(tmp, vtg->regs + VTG_BOT_V_HD_3); 168*f2cb3148SBenjamin Gaignard 169*f2cb3148SBenjamin Gaignard /* mode */ 170*f2cb3148SBenjamin Gaignard writel(type, vtg->regs + VTG_MODE); 171*f2cb3148SBenjamin Gaignard } 172*f2cb3148SBenjamin Gaignard 173*f2cb3148SBenjamin Gaignard static void vtg_enable_irq(struct sti_vtg *vtg) 174*f2cb3148SBenjamin Gaignard { 175*f2cb3148SBenjamin Gaignard /* clear interrupt status and mask */ 176*f2cb3148SBenjamin Gaignard writel(0xFFFF, vtg->regs + VTG_HOST_ITS_BCLR); 177*f2cb3148SBenjamin Gaignard writel(0xFFFF, vtg->regs + VTG_HOST_ITM_BCLR); 178*f2cb3148SBenjamin Gaignard writel(VTG_IRQ_MASK, vtg->regs + VTG_HOST_ITM_BSET); 179*f2cb3148SBenjamin Gaignard } 180*f2cb3148SBenjamin Gaignard 181*f2cb3148SBenjamin Gaignard void sti_vtg_set_config(struct sti_vtg *vtg, 182*f2cb3148SBenjamin Gaignard const struct drm_display_mode *mode) 183*f2cb3148SBenjamin Gaignard { 184*f2cb3148SBenjamin Gaignard /* write configuration */ 185*f2cb3148SBenjamin Gaignard vtg_set_mode(vtg, VTG_TYPE_MASTER, mode); 186*f2cb3148SBenjamin Gaignard 187*f2cb3148SBenjamin Gaignard vtg_reset(vtg); 188*f2cb3148SBenjamin Gaignard 189*f2cb3148SBenjamin Gaignard /* enable irq for the vtg vblank synchro */ 190*f2cb3148SBenjamin Gaignard if (vtg->slave) 191*f2cb3148SBenjamin Gaignard vtg_enable_irq(vtg->slave); 192*f2cb3148SBenjamin Gaignard else 193*f2cb3148SBenjamin Gaignard vtg_enable_irq(vtg); 194*f2cb3148SBenjamin Gaignard } 195*f2cb3148SBenjamin Gaignard EXPORT_SYMBOL(sti_vtg_set_config); 196*f2cb3148SBenjamin Gaignard 197*f2cb3148SBenjamin Gaignard /** 198*f2cb3148SBenjamin Gaignard * sti_vtg_get_line_number 199*f2cb3148SBenjamin Gaignard * 200*f2cb3148SBenjamin Gaignard * @mode: display mode to be used 201*f2cb3148SBenjamin Gaignard * @y: line 202*f2cb3148SBenjamin Gaignard * 203*f2cb3148SBenjamin Gaignard * Return the line number according to the display mode taking 204*f2cb3148SBenjamin Gaignard * into account the Sync and Back Porch information. 205*f2cb3148SBenjamin Gaignard * Video frame line numbers start at 1, y starts at 0. 206*f2cb3148SBenjamin Gaignard * In interlaced modes the start line is the field line number of the odd 207*f2cb3148SBenjamin Gaignard * field, but y is still defined as a progressive frame. 208*f2cb3148SBenjamin Gaignard */ 209*f2cb3148SBenjamin Gaignard u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y) 210*f2cb3148SBenjamin Gaignard { 211*f2cb3148SBenjamin Gaignard u32 start_line = mode.vtotal - mode.vsync_start + 1; 212*f2cb3148SBenjamin Gaignard 213*f2cb3148SBenjamin Gaignard if (mode.flags & DRM_MODE_FLAG_INTERLACE) 214*f2cb3148SBenjamin Gaignard start_line *= 2; 215*f2cb3148SBenjamin Gaignard 216*f2cb3148SBenjamin Gaignard return start_line + y; 217*f2cb3148SBenjamin Gaignard } 218*f2cb3148SBenjamin Gaignard EXPORT_SYMBOL(sti_vtg_get_line_number); 219*f2cb3148SBenjamin Gaignard 220*f2cb3148SBenjamin Gaignard /** 221*f2cb3148SBenjamin Gaignard * sti_vtg_get_pixel_number 222*f2cb3148SBenjamin Gaignard * 223*f2cb3148SBenjamin Gaignard * @mode: display mode to be used 224*f2cb3148SBenjamin Gaignard * @x: row 225*f2cb3148SBenjamin Gaignard * 226*f2cb3148SBenjamin Gaignard * Return the pixel number according to the display mode taking 227*f2cb3148SBenjamin Gaignard * into account the Sync and Back Porch information. 228*f2cb3148SBenjamin Gaignard * Pixels are counted from 0. 229*f2cb3148SBenjamin Gaignard */ 230*f2cb3148SBenjamin Gaignard u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x) 231*f2cb3148SBenjamin Gaignard { 232*f2cb3148SBenjamin Gaignard return mode.htotal - mode.hsync_start + x; 233*f2cb3148SBenjamin Gaignard } 234*f2cb3148SBenjamin Gaignard EXPORT_SYMBOL(sti_vtg_get_pixel_number); 235*f2cb3148SBenjamin Gaignard 236*f2cb3148SBenjamin Gaignard int sti_vtg_register_client(struct sti_vtg *vtg, 237*f2cb3148SBenjamin Gaignard struct notifier_block *nb, int crtc_id) 238*f2cb3148SBenjamin Gaignard { 239*f2cb3148SBenjamin Gaignard if (vtg->slave) 240*f2cb3148SBenjamin Gaignard return sti_vtg_register_client(vtg->slave, nb, crtc_id); 241*f2cb3148SBenjamin Gaignard 242*f2cb3148SBenjamin Gaignard vtg->crtc_id = crtc_id; 243*f2cb3148SBenjamin Gaignard return raw_notifier_chain_register(&vtg->notifier_list, nb); 244*f2cb3148SBenjamin Gaignard } 245*f2cb3148SBenjamin Gaignard EXPORT_SYMBOL(sti_vtg_register_client); 246*f2cb3148SBenjamin Gaignard 247*f2cb3148SBenjamin Gaignard int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb) 248*f2cb3148SBenjamin Gaignard { 249*f2cb3148SBenjamin Gaignard if (vtg->slave) 250*f2cb3148SBenjamin Gaignard return sti_vtg_unregister_client(vtg->slave, nb); 251*f2cb3148SBenjamin Gaignard 252*f2cb3148SBenjamin Gaignard return raw_notifier_chain_unregister(&vtg->notifier_list, nb); 253*f2cb3148SBenjamin Gaignard } 254*f2cb3148SBenjamin Gaignard EXPORT_SYMBOL(sti_vtg_unregister_client); 255*f2cb3148SBenjamin Gaignard 256*f2cb3148SBenjamin Gaignard static irqreturn_t vtg_irq_thread(int irq, void *arg) 257*f2cb3148SBenjamin Gaignard { 258*f2cb3148SBenjamin Gaignard struct sti_vtg *vtg = arg; 259*f2cb3148SBenjamin Gaignard u32 event; 260*f2cb3148SBenjamin Gaignard 261*f2cb3148SBenjamin Gaignard event = (vtg->irq_status & VTG_IRQ_TOP) ? 262*f2cb3148SBenjamin Gaignard VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT; 263*f2cb3148SBenjamin Gaignard 264*f2cb3148SBenjamin Gaignard raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id); 265*f2cb3148SBenjamin Gaignard 266*f2cb3148SBenjamin Gaignard return IRQ_HANDLED; 267*f2cb3148SBenjamin Gaignard } 268*f2cb3148SBenjamin Gaignard 269*f2cb3148SBenjamin Gaignard static irqreturn_t vtg_irq(int irq, void *arg) 270*f2cb3148SBenjamin Gaignard { 271*f2cb3148SBenjamin Gaignard struct sti_vtg *vtg = arg; 272*f2cb3148SBenjamin Gaignard 273*f2cb3148SBenjamin Gaignard vtg->irq_status = readl(vtg->regs + VTG_HOST_ITS); 274*f2cb3148SBenjamin Gaignard 275*f2cb3148SBenjamin Gaignard writel(vtg->irq_status, vtg->regs + VTG_HOST_ITS_BCLR); 276*f2cb3148SBenjamin Gaignard 277*f2cb3148SBenjamin Gaignard /* force sync bus write */ 278*f2cb3148SBenjamin Gaignard readl(vtg->regs + VTG_HOST_ITS); 279*f2cb3148SBenjamin Gaignard 280*f2cb3148SBenjamin Gaignard return IRQ_WAKE_THREAD; 281*f2cb3148SBenjamin Gaignard } 282*f2cb3148SBenjamin Gaignard 283*f2cb3148SBenjamin Gaignard static int vtg_probe(struct platform_device *pdev) 284*f2cb3148SBenjamin Gaignard { 285*f2cb3148SBenjamin Gaignard struct device *dev = &pdev->dev; 286*f2cb3148SBenjamin Gaignard struct device_node *np; 287*f2cb3148SBenjamin Gaignard struct sti_vtg *vtg; 288*f2cb3148SBenjamin Gaignard struct resource *res; 289*f2cb3148SBenjamin Gaignard char irq_name[32]; 290*f2cb3148SBenjamin Gaignard int ret; 291*f2cb3148SBenjamin Gaignard 292*f2cb3148SBenjamin Gaignard vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL); 293*f2cb3148SBenjamin Gaignard if (!vtg) 294*f2cb3148SBenjamin Gaignard return -ENOMEM; 295*f2cb3148SBenjamin Gaignard 296*f2cb3148SBenjamin Gaignard vtg->dev = dev; 297*f2cb3148SBenjamin Gaignard vtg->np = pdev->dev.of_node; 298*f2cb3148SBenjamin Gaignard 299*f2cb3148SBenjamin Gaignard /* Get Memory ressources */ 300*f2cb3148SBenjamin Gaignard res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 301*f2cb3148SBenjamin Gaignard if (!res) { 302*f2cb3148SBenjamin Gaignard DRM_ERROR("Get memory resource failed\n"); 303*f2cb3148SBenjamin Gaignard return -ENOMEM; 304*f2cb3148SBenjamin Gaignard } 305*f2cb3148SBenjamin Gaignard vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 306*f2cb3148SBenjamin Gaignard 307*f2cb3148SBenjamin Gaignard np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0); 308*f2cb3148SBenjamin Gaignard if (np) { 309*f2cb3148SBenjamin Gaignard vtg->slave = of_vtg_find(np); 310*f2cb3148SBenjamin Gaignard 311*f2cb3148SBenjamin Gaignard if (!vtg->slave) 312*f2cb3148SBenjamin Gaignard return -EPROBE_DEFER; 313*f2cb3148SBenjamin Gaignard } else { 314*f2cb3148SBenjamin Gaignard vtg->irq = platform_get_irq(pdev, 0); 315*f2cb3148SBenjamin Gaignard if (IS_ERR_VALUE(vtg->irq)) { 316*f2cb3148SBenjamin Gaignard DRM_ERROR("Failed to get VTG interrupt\n"); 317*f2cb3148SBenjamin Gaignard return vtg->irq; 318*f2cb3148SBenjamin Gaignard } 319*f2cb3148SBenjamin Gaignard 320*f2cb3148SBenjamin Gaignard snprintf(irq_name, sizeof(irq_name), "vsync-%s", 321*f2cb3148SBenjamin Gaignard dev_name(vtg->dev)); 322*f2cb3148SBenjamin Gaignard 323*f2cb3148SBenjamin Gaignard RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list); 324*f2cb3148SBenjamin Gaignard 325*f2cb3148SBenjamin Gaignard ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq, 326*f2cb3148SBenjamin Gaignard vtg_irq_thread, IRQF_ONESHOT, irq_name, vtg); 327*f2cb3148SBenjamin Gaignard if (IS_ERR_VALUE(ret)) { 328*f2cb3148SBenjamin Gaignard DRM_ERROR("Failed to register VTG interrupt\n"); 329*f2cb3148SBenjamin Gaignard return ret; 330*f2cb3148SBenjamin Gaignard } 331*f2cb3148SBenjamin Gaignard } 332*f2cb3148SBenjamin Gaignard 333*f2cb3148SBenjamin Gaignard vtg_register(vtg); 334*f2cb3148SBenjamin Gaignard platform_set_drvdata(pdev, vtg); 335*f2cb3148SBenjamin Gaignard 336*f2cb3148SBenjamin Gaignard DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev)); 337*f2cb3148SBenjamin Gaignard 338*f2cb3148SBenjamin Gaignard return 0; 339*f2cb3148SBenjamin Gaignard } 340*f2cb3148SBenjamin Gaignard 341*f2cb3148SBenjamin Gaignard static int vtg_remove(struct platform_device *pdev) 342*f2cb3148SBenjamin Gaignard { 343*f2cb3148SBenjamin Gaignard return 0; 344*f2cb3148SBenjamin Gaignard } 345*f2cb3148SBenjamin Gaignard 346*f2cb3148SBenjamin Gaignard static const struct of_device_id vtg_of_match[] = { 347*f2cb3148SBenjamin Gaignard { .compatible = "st,vtg", }, 348*f2cb3148SBenjamin Gaignard { /* sentinel */ } 349*f2cb3148SBenjamin Gaignard }; 350*f2cb3148SBenjamin Gaignard MODULE_DEVICE_TABLE(of, vtg_of_match); 351*f2cb3148SBenjamin Gaignard 352*f2cb3148SBenjamin Gaignard struct platform_driver sti_vtg_driver = { 353*f2cb3148SBenjamin Gaignard .driver = { 354*f2cb3148SBenjamin Gaignard .name = "sti-vtg", 355*f2cb3148SBenjamin Gaignard .owner = THIS_MODULE, 356*f2cb3148SBenjamin Gaignard .of_match_table = vtg_of_match, 357*f2cb3148SBenjamin Gaignard }, 358*f2cb3148SBenjamin Gaignard .probe = vtg_probe, 359*f2cb3148SBenjamin Gaignard .remove = vtg_remove, 360*f2cb3148SBenjamin Gaignard }; 361*f2cb3148SBenjamin Gaignard 362*f2cb3148SBenjamin Gaignard module_platform_driver(sti_vtg_driver); 363*f2cb3148SBenjamin Gaignard 364*f2cb3148SBenjamin Gaignard MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 365*f2cb3148SBenjamin Gaignard MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 366*f2cb3148SBenjamin Gaignard MODULE_LICENSE("GPL"); 367