@@ -1370,6 +1370,113 @@ static int sm501_init_dev(struct sm501_devdata *sm)
return 0;
}
+#ifdef CONFIG_OF
+static unsigned int sm501_parse_devices_str(struct device_node *np)
+{
+ unsigned int device = 0;
+ unsigned int i, j;
+ unsigned int nstr;
+ const char *devstr;
+ static const struct {
+ char *devname;
+ unsigned int devid;
+ } devlist[] = {
+ { "usb-host", SM501_USE_USB_HOST },
+ { "usb-gadget", SM501_USE_USB_SLAVE },
+ { "ssp0", SM501_USE_SSP0 },
+ { "ssp1", SM501_USE_SSP1 },
+ { "uart0", SM501_USE_UART0 },
+ { "uart1", SM501_USE_UART1 },
+ { "accel", SM501_USE_FBACCEL },
+ { "ac97", SM501_USE_AC97 },
+ { "i2s", SM501_USE_I2S },
+ { "gpio", SM501_USE_GPIO },
+ { "all", SM501_USE_ALL },
+ };
+
+ nstr = of_property_count_strings(np, "smi,devices");
+ for (i = 0; i < nstr; i++) {
+ if (of_property_read_string_index(np, "smi,devices", i, &devstr))
+ break;
+ for (j = 0; j < ARRAY_SIZE(devlist); j++) {
+ if (strcmp(devstr, devlist[j].devname) == 0) {
+ device |= devlist[j].devid;
+ goto next;
+ }
+ }
+next:
+ }
+ return device;
+}
+
+static void sm501_of_read_reg_init(struct device_node *np,
+ const char *propname, struct sm501_reg_init *val)
+{
+ u32 u32_val[2];
+
+ if (!of_property_read_u32_array(np, propname, u32_val, sizeof(u32_val))) {
+ val->set = u32_val[0];
+ val->mask = u32_val[1];
+ } else {
+ val->set = 0;
+ val->mask = 0;
+ }
+}
+
+static int sm501_parse_dt(struct sm501_devdata *sm, struct device_node *np)
+{
+ struct sm501_platdata *plat;
+ u32 u32_val;
+
+ plat = devm_kzalloc(sm->dev, sizeof(*plat), GFP_KERNEL);
+ if (!plat)
+ return -ENOMEM;
+
+ plat->init = devm_kzalloc(sm->dev, sizeof(*plat->init), GFP_KERNEL);
+ if (!plat->init)
+ return -ENOMEM;
+
+ plat->init->devices = sm501_parse_devices_str(np);
+
+ if (!of_property_read_u32_index(np, "smi,mclk", 0, &u32_val))
+ plat->init->mclk = u32_val;
+ else
+ plat->init->mclk = 0;
+
+ if (!of_property_read_u32_index(np, "smi,m1xclk", 0, &u32_val))
+ plat->init->m1xclk = u32_val;
+ else
+ plat->init->m1xclk = 0;
+
+ sm501_of_read_reg_init(np, "smi,misc-timing", &plat->init->misc_timing);
+ sm501_of_read_reg_init(np, "smi,misc-control", &plat->init->misc_control);
+ sm501_of_read_reg_init(np, "smi,gpio-low", &plat->init->gpio_low);
+ sm501_of_read_reg_init(np, "smi,gpio-high", &plat->init->gpio_high);
+
+#ifdef CONFIG_MFD_SM501_GPIO
+ if (plat->init->devices & SM501_USE_GPIO) {
+ if (!of_property_read_u32_index(np, "smi,num-i2c", 0, &u32_val))
+ plat->gpio_i2c_nr = u32_val;
+ else
+ plat->gpio_i2c_nr = 0;
+ }
+ if (plat->gpio_i2c_nr > 0) {
+ int sz_gpio;
+
+ sz_gpio = sizeof(struct sm501_platdata_gpio_i2c) * plat->gpio_i2c_nr;
+ plat->gpio_i2c = devm_kzalloc(sm->dev, sz_gpio, GFP_KERNEL);
+ if (plat->gpio_i2c == NULL)
+ return -ENOMEM;
+
+ of_property_read_variable_u32(np, "smi,gpio-i2c",
+ plat->gpio_i2c, plat->gpio_i2c_nr * 5);
+ }
+#endif /* CONFIG_MFD_SM501_GPIO */
+ sm->platdata = plat;
+ return 0;
+}
+#endif /* CONFIG_OF */
+
static int sm501_plat_probe(struct platform_device *dev)
{
struct sm501_devdata *sm;
@@ -1406,6 +1513,12 @@ static int sm501_plat_probe(struct platform_device *dev)
goto err_res;
}
+ if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node) {
+ ret = sm501_parse_dt(sm, dev->dev.of_node);
+ if (ret)
+ goto err_res;
+ }
+
platform_set_drvdata(dev, sm);
sm->regs = ioremap(sm->io_res->start, resource_size(sm->io_res));
@@ -1928,6 +1928,82 @@ static int sm501fb_start_one(struct sm501fb_info *info,
return 0;
}
+#if defined(CONFIG_OF)
+static struct sm501_platdata_fbsub *read_fbsub(struct device_node *np, const char *ch_name)
+{
+ struct device_node *child;
+ struct sm501_platdata_fbsub *fbsub = NULL;
+ struct fb_videomode *def_mode;
+ u32 bpp;
+ u32 max_mem;
+ u32 flags = 0;
+ static const char * const flag_str[] = {
+ "use_init_mode",
+ "disable_at_exit",
+ "use_hwcursor",
+ "use_hwaccel",
+ "panel_no_fpen",
+ "panel_no_vbiasen",
+ "panel_inv_fpen",
+ "panel_inv_vbiasen",
+ };
+ const char *flag_value;
+ const char *prop;
+ int nr_flags;
+ int i, j;
+ int len;
+
+ child = of_get_child_by_name(np, ch_name);
+ if (child == NULL)
+ return NULL;
+
+ prop = of_get_property(child, "edid", &len);
+ if (prop && len == EDID_LENGTH) {
+ struct fb_monspecs *specs;
+ u8 *edid;
+
+ edid = kmemdup(prop, EDID_LENGTH, GFP_KERNEL);
+ if (edid) {
+ specs = kzalloc(sizeof(*specs), GFP_KERNEL);
+ if (specs) {
+ fb_edid_to_monspecs(edid, specs);
+ def_mode = specs->modedb;
+ }
+ kfree(specs);
+ }
+ kfree(edid);
+ }
+
+ if (of_property_read_u32(child, "bpp", &bpp))
+ bpp = 0;
+ if (of_property_read_u32(child, "max-mem", &max_mem))
+ max_mem = 0;
+
+ nr_flags = of_property_count_strings(child, "flags");
+ for (i = 0; i < nr_flags; i++) {
+ if (of_property_read_string_index(child, "flags", i, &flag_value) < 0)
+ break;
+ for (j = 0; j < ARRAY_SIZE(flag_str); j++) {
+ if (strcasecmp(flag_value, flag_str[j]) == 0) {
+ flags |= 1 << j;
+ break;
+ }
+ }
+ }
+
+ if (def_mode || bpp || max_mem || flags) {
+ fbsub = kzalloc(sizeof(*fbsub), GFP_KERNEL);
+ if (fbsub) {
+ fbsub->def_mode = def_mode;
+ fbsub->def_bpp = bpp;
+ fbsub->max_mem = max_mem;
+ fbsub->flags = flags;
+ }
+ }
+ return fbsub;
+}
+#endif
+
static int sm501fb_probe(struct platform_device *pdev)
{
struct sm501fb_info *info;
@@ -1956,6 +2032,7 @@ static int sm501fb_probe(struct platform_device *pdev)
const u8 *prop;
const char *cp;
int len;
+ struct sm501_platdata_fbsub *sub;
info->pdata = &sm501fb_def_pdata;
if (np) {
@@ -1970,6 +2047,21 @@ static int sm501fb_probe(struct platform_device *pdev)
if (info->edid_data)
found = 1;
}
+ cp = of_get_property(np, "route", &len);
+ if (cp) {
+ if (strcasecmp(cp, "own") == 0)
+ info->pdata->fb_route = SM501_FB_OWN;
+ else if (strcasecmp(cp, "crt-panel") == 0)
+ info->pdata->fb_route = SM501_FB_CRT_PANEL;
+ }
+ if (of_property_read_bool(np, "swap-fb-endian"))
+ info->pdata->flags |= SM501_FBPD_SWAP_FB_ENDIAN;
+ sub = read_fbsub(np, "crt");
+ if (sub)
+ info->pdata->fb_crt = sub;
+ sub = read_fbsub(np, "panel");
+ if (sub)
+ info->pdata->fb_pnl = sub;
}
#endif
if (!found) {
I am changing the target board of SuperH using SM501 to DeviceTree. This target uses platform_device to configure sm501 and sm501fb. In order to migrate to DeviceTree, it can now be set in properties. Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp> --- drivers/mfd/sm501.c | 113 ++++++++++++++++++++++++++++++++++ drivers/video/fbdev/sm501fb.c | 92 +++++++++++++++++++++++++++ 2 files changed, 205 insertions(+)