static void panel_destroy(struct tilcdc_module *mod) { struct panel_module *panel_mod = to_panel_module(mod); if (panel_mod->timings) display_timings_release(panel_mod->timings); tilcdc_module_cleanup(mod); kfree(panel_mod->info); kfree(panel_mod); }
static int panel_remove(struct platform_device *pdev) { struct tilcdc_module *mod = dev_get_platdata(&pdev->dev); struct panel_module *panel_mod = to_panel_module(mod); struct backlight_device *backlight = panel_mod->backlight; if (backlight) put_device(&backlight->dev); display_timings_release(panel_mod->timings); tilcdc_module_cleanup(mod); kfree(panel_mod->info); return 0; }
/** * of_get_display_timings - parse all display_timing entries from a device_node * @np: device_node with the subnodes **/ struct display_timings *of_get_display_timings(struct device_node *np) { struct device_node *timings_np; struct device_node *entry; struct device_node *native_mode; struct display_timings *disp; if (!np) { pr_err("%s: no devicenode given\n", of_node_full_name(np)); return NULL; } timings_np = of_find_node_by_name(np, "display-timings"); if (!timings_np) { pr_err("%s: could not find display-timings node\n", of_node_full_name(np)); return NULL; } disp = kzalloc(sizeof(*disp), GFP_KERNEL); if (!disp) { pr_err("%s: could not allocate struct disp'\n", of_node_full_name(np)); goto dispfail; } entry = of_parse_phandle(timings_np, "native-mode", 0); /* assume first child as native mode if none provided */ if (!entry) entry = of_get_next_child(np, NULL); /* if there is no child, it is useless to go on */ if (!entry) { pr_err("%s: no timing specifications given\n", of_node_full_name(np)); goto entryfail; } pr_debug("%s: using %s as default timing\n", of_node_full_name(np), entry->name); native_mode = entry; disp->num_timings = of_get_child_count(timings_np); if (disp->num_timings == 0) { /* should never happen, as entry was already found above */ pr_err("%s: no timings specified\n", of_node_full_name(np)); goto entryfail; } disp->timings = kzalloc(sizeof(struct display_timing *) * disp->num_timings, GFP_KERNEL); if (!disp->timings) { pr_err("%s: could not allocate timings array\n", of_node_full_name(np)); goto entryfail; } disp->num_timings = 0; disp->native_mode = 0; for_each_child_of_node(timings_np, entry) { struct display_timing *dt; dt = of_get_display_timing(entry); if (!dt) { /* * to not encourage wrong devicetrees, fail in case of * an error */ pr_err("%s: error in timing %d\n", of_node_full_name(np), disp->num_timings + 1); goto timingfail; } if (native_mode == entry) disp->native_mode = disp->num_timings; disp->timings[disp->num_timings] = dt; disp->num_timings++; } of_node_put(timings_np); /* * native_mode points to the device_node returned by of_parse_phandle * therefore call of_node_put on it */ of_node_put(native_mode); pr_debug("%s: got %d timings. Using timing #%d as default\n", of_node_full_name(np), disp->num_timings, disp->native_mode + 1); return disp; timingfail: if (native_mode) of_node_put(native_mode); display_timings_release(disp); entryfail: kfree(disp); dispfail: of_node_put(timings_np); return NULL; }
static int panel_probe(struct platform_device *pdev) { struct device_node *bl_node, *node = pdev->dev.of_node; struct panel_module *panel_mod; struct tilcdc_module *mod; struct pinctrl *pinctrl; int ret; /* bail out early if no DT data: */ if (!node) { dev_err(&pdev->dev, "device-tree data is missing\n"); return -ENXIO; } panel_mod = devm_kzalloc(&pdev->dev, sizeof(*panel_mod), GFP_KERNEL); if (!panel_mod) return -ENOMEM; bl_node = of_parse_phandle(node, "backlight", 0); if (bl_node) { panel_mod->backlight = of_find_backlight_by_node(bl_node); of_node_put(bl_node); if (!panel_mod->backlight) return -EPROBE_DEFER; dev_info(&pdev->dev, "found backlight\n"); } panel_mod->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(panel_mod->enable_gpio)) { ret = PTR_ERR(panel_mod->enable_gpio); dev_err(&pdev->dev, "failed to request enable GPIO\n"); goto fail_backlight; } if (panel_mod->enable_gpio) dev_info(&pdev->dev, "found enable GPIO\n"); mod = &panel_mod->base; pdev->dev.platform_data = mod; tilcdc_module_init(mod, "panel", &panel_module_ops); pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) dev_warn(&pdev->dev, "pins are not configured\n"); panel_mod->timings = of_get_display_timings(node); if (!panel_mod->timings) { dev_err(&pdev->dev, "could not get panel timings\n"); ret = -EINVAL; goto fail_free; } panel_mod->info = of_get_panel_info(node); if (!panel_mod->info) { dev_err(&pdev->dev, "could not get panel info\n"); ret = -EINVAL; goto fail_timings; } mod->preferred_bpp = panel_mod->info->bpp; return 0; fail_timings: display_timings_release(panel_mod->timings); fail_free: tilcdc_module_cleanup(mod); fail_backlight: if (panel_mod->backlight) put_device(&panel_mod->backlight->dev); return ret; }