diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2011-09-18 06:25:21 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2012-03-12 17:40:51 -0400 |
commit | bce95fe838a5ca84e57411338b953be672c2a5eb (patch) | |
tree | ab99cb3ef78de9677b83c45e27e2372fa4cc3d6b /drivers | |
parent | e34d0bbb062cc78802d0f0686c939ea1569889a6 (diff) |
sh_mobile_hdmi: Use sh_mobile_lcdc_entity::channel to access fb_info
The fb_info parameter passed to the display_on operation will be
removed, don't use it.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/sh_mobile_hdmi.c | 80 |
1 files changed, 12 insertions, 68 deletions
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 3f4e4a4c1cd8..bd885ee78d54 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c | |||
@@ -219,16 +219,12 @@ struct sh_hdmi { | |||
219 | u8 edid_blocks; | 219 | u8 edid_blocks; |
220 | struct clk *hdmi_clk; | 220 | struct clk *hdmi_clk; |
221 | struct device *dev; | 221 | struct device *dev; |
222 | struct fb_info *info; | ||
223 | struct mutex mutex; /* Protect the info pointer */ | ||
224 | struct delayed_work edid_work; | 222 | struct delayed_work edid_work; |
225 | struct fb_var_screeninfo var; | 223 | struct fb_var_screeninfo var; |
226 | struct fb_monspecs monspec; | 224 | struct fb_monspecs monspec; |
227 | struct notifier_block notifier; | ||
228 | }; | 225 | }; |
229 | 226 | ||
230 | #define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) | 227 | #define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) |
231 | #define notifier_to_hdmi(n) container_of(n, struct sh_hdmi, notifier) | ||
232 | 228 | ||
233 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | 229 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) |
234 | { | 230 | { |
@@ -737,10 +733,11 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, | |||
737 | static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, | 733 | static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, |
738 | unsigned long *parent_rate) | 734 | unsigned long *parent_rate) |
739 | { | 735 | { |
736 | struct fb_info *info = hdmi->entity.lcdc | ||
737 | ? hdmi->entity.lcdc->info : NULL; | ||
740 | struct fb_var_screeninfo tmpvar; | 738 | struct fb_var_screeninfo tmpvar; |
741 | struct fb_var_screeninfo *var = &tmpvar; | 739 | struct fb_var_screeninfo *var = &tmpvar; |
742 | const struct fb_videomode *mode, *found = NULL; | 740 | const struct fb_videomode *mode, *found = NULL; |
743 | struct fb_info *info = hdmi->info; | ||
744 | struct fb_modelist *modelist = NULL; | 741 | struct fb_modelist *modelist = NULL; |
745 | unsigned int f_width = 0, f_height = 0, f_refresh = 0; | 742 | unsigned int f_width = 0, f_height = 0, f_refresh = 0; |
746 | unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ | 743 | unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ |
@@ -1012,13 +1009,10 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity, | |||
1012 | * FB_EVENT_FB_UNBIND notify is also called with info->lock held | 1009 | * FB_EVENT_FB_UNBIND notify is also called with info->lock held |
1013 | */ | 1010 | */ |
1014 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); | 1011 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); |
1015 | struct sh_mobile_lcdc_chan *ch = info->par; | 1012 | struct sh_mobile_lcdc_chan *ch = entity->lcdc; |
1016 | 1013 | ||
1017 | dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, info->state); | 1014 | dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, info->state); |
1018 | 1015 | ||
1019 | /* No need to lock */ | ||
1020 | hdmi->info = info; | ||
1021 | |||
1022 | /* | 1016 | /* |
1023 | * hp_state can be set to | 1017 | * hp_state can be set to |
1024 | * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug | 1018 | * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug |
@@ -1040,7 +1034,6 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity, | |||
1040 | return 0; | 1034 | return 0; |
1041 | } | 1035 | } |
1042 | 1036 | ||
1043 | /* locking: called with info->lock held */ | ||
1044 | static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) | 1037 | static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) |
1045 | { | 1038 | { |
1046 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); | 1039 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); |
@@ -1057,15 +1050,14 @@ static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = { | |||
1057 | 1050 | ||
1058 | static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) | 1051 | static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) |
1059 | { | 1052 | { |
1060 | struct fb_info *info = hdmi->info; | 1053 | struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc; |
1061 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
1062 | struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; | 1054 | struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; |
1063 | struct fb_videomode mode1, mode2; | 1055 | struct fb_videomode mode1, mode2; |
1064 | 1056 | ||
1065 | fb_var_to_videomode(&mode1, old_var); | 1057 | fb_var_to_videomode(&mode1, old_var); |
1066 | fb_var_to_videomode(&mode2, new_var); | 1058 | fb_var_to_videomode(&mode2, new_var); |
1067 | 1059 | ||
1068 | dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", | 1060 | dev_dbg(hdmi->dev, "Old %ux%u, new %ux%u\n", |
1069 | mode1.xres, mode1.yres, mode2.xres, mode2.yres); | 1061 | mode1.xres, mode1.yres, mode2.xres, mode2.yres); |
1070 | 1062 | ||
1071 | if (fb_mode_is_equal(&mode1, &mode2)) { | 1063 | if (fb_mode_is_equal(&mode1, &mode2)) { |
@@ -1075,7 +1067,7 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) | |||
1075 | return false; | 1067 | return false; |
1076 | } | 1068 | } |
1077 | 1069 | ||
1078 | dev_dbg(info->dev, "Switching %u -> %u lines\n", | 1070 | dev_dbg(hdmi->dev, "Switching %u -> %u lines\n", |
1079 | mode1.yres, mode2.yres); | 1071 | mode1.yres, mode2.yres); |
1080 | *old_var = *new_var; | 1072 | *old_var = *new_var; |
1081 | 1073 | ||
@@ -1121,17 +1113,13 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, | |||
1121 | static void sh_hdmi_edid_work_fn(struct work_struct *work) | 1113 | static void sh_hdmi_edid_work_fn(struct work_struct *work) |
1122 | { | 1114 | { |
1123 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); | 1115 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); |
1116 | struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc; | ||
1124 | struct fb_info *info; | 1117 | struct fb_info *info; |
1125 | struct sh_mobile_lcdc_chan *ch; | ||
1126 | int ret; | 1118 | int ret; |
1127 | 1119 | ||
1128 | dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi, | 1120 | dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi, |
1129 | hdmi->hp_state); | 1121 | hdmi->hp_state); |
1130 | 1122 | ||
1131 | mutex_lock(&hdmi->mutex); | ||
1132 | |||
1133 | info = hdmi->info; | ||
1134 | |||
1135 | if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { | 1123 | if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { |
1136 | unsigned long parent_rate = 0, hdmi_rate; | 1124 | unsigned long parent_rate = 0, hdmi_rate; |
1137 | 1125 | ||
@@ -1151,10 +1139,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) | |||
1151 | /* Switched to another (d) power-save mode */ | 1139 | /* Switched to another (d) power-save mode */ |
1152 | msleep(10); | 1140 | msleep(10); |
1153 | 1141 | ||
1154 | if (!info) | 1142 | if (ch == NULL) |
1155 | goto out; | 1143 | goto out; |
1156 | 1144 | ||
1157 | ch = info->par; | 1145 | info = ch->info; |
1158 | 1146 | ||
1159 | if (lock_fb_info(info)) { | 1147 | if (lock_fb_info(info)) { |
1160 | console_lock(); | 1148 | console_lock(); |
@@ -1179,9 +1167,11 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) | |||
1179 | } | 1167 | } |
1180 | } else { | 1168 | } else { |
1181 | ret = 0; | 1169 | ret = 0; |
1182 | if (!info) | 1170 | if (ch == NULL) |
1183 | goto out; | 1171 | goto out; |
1184 | 1172 | ||
1173 | info = ch->info; | ||
1174 | |||
1185 | hdmi->monspec.modedb_len = 0; | 1175 | hdmi->monspec.modedb_len = 0; |
1186 | fb_destroy_modedb(hdmi->monspec.modedb); | 1176 | fb_destroy_modedb(hdmi->monspec.modedb); |
1187 | hdmi->monspec.modedb = NULL; | 1177 | hdmi->monspec.modedb = NULL; |
@@ -1200,47 +1190,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) | |||
1200 | out: | 1190 | out: |
1201 | if (ret < 0 && ret != -EAGAIN) | 1191 | if (ret < 0 && ret != -EAGAIN) |
1202 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; | 1192 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; |
1203 | mutex_unlock(&hdmi->mutex); | ||
1204 | 1193 | ||
1205 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); | 1194 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); |
1206 | } | 1195 | } |
1207 | 1196 | ||
1208 | static int sh_hdmi_notify(struct notifier_block *nb, | ||
1209 | unsigned long action, void *data) | ||
1210 | { | ||
1211 | struct fb_event *event = data; | ||
1212 | struct fb_info *info = event->info; | ||
1213 | struct sh_hdmi *hdmi = notifier_to_hdmi(nb); | ||
1214 | |||
1215 | if (hdmi->info != info) | ||
1216 | return NOTIFY_DONE; | ||
1217 | |||
1218 | switch(action) { | ||
1219 | case FB_EVENT_FB_REGISTERED: | ||
1220 | /* Unneeded, activation taken care by sh_hdmi_display_on() */ | ||
1221 | break; | ||
1222 | case FB_EVENT_FB_UNREGISTERED: | ||
1223 | /* | ||
1224 | * We are called from unregister_framebuffer() with the | ||
1225 | * info->lock held. This is bad for us, because we can race with | ||
1226 | * the scheduled work, which has to call fb_set_suspend(), which | ||
1227 | * takes info->lock internally, so, sh_hdmi_edid_work_fn() | ||
1228 | * cannot take and hold info->lock for the whole function | ||
1229 | * duration. Using an additional lock creates a classical AB-BA | ||
1230 | * lock up. Therefore, we have to release the info->lock | ||
1231 | * temporarily, synchronise with the work queue and re-acquire | ||
1232 | * the info->lock. | ||
1233 | */ | ||
1234 | unlock_fb_info(info); | ||
1235 | mutex_lock(&hdmi->mutex); | ||
1236 | hdmi->info = NULL; | ||
1237 | mutex_unlock(&hdmi->mutex); | ||
1238 | lock_fb_info(info); | ||
1239 | return NOTIFY_OK; | ||
1240 | } | ||
1241 | return NOTIFY_DONE; | ||
1242 | } | ||
1243 | |||
1244 | static int __init sh_hdmi_probe(struct platform_device *pdev) | 1197 | static int __init sh_hdmi_probe(struct platform_device *pdev) |
1245 | { | 1198 | { |
1246 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1199 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
@@ -1258,8 +1211,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1258 | return -ENOMEM; | 1211 | return -ENOMEM; |
1259 | } | 1212 | } |
1260 | 1213 | ||
1261 | mutex_init(&hdmi->mutex); | ||
1262 | |||
1263 | hdmi->dev = &pdev->dev; | 1214 | hdmi->dev = &pdev->dev; |
1264 | hdmi->entity.owner = THIS_MODULE; | 1215 | hdmi->entity.owner = THIS_MODULE; |
1265 | hdmi->entity.ops = &sh_hdmi_ops; | 1216 | hdmi->entity.ops = &sh_hdmi_ops; |
@@ -1327,9 +1278,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1327 | goto ecodec; | 1278 | goto ecodec; |
1328 | } | 1279 | } |
1329 | 1280 | ||
1330 | hdmi->notifier.notifier_call = sh_hdmi_notify; | ||
1331 | fb_register_client(&hdmi->notifier); | ||
1332 | |||
1333 | return 0; | 1281 | return 0; |
1334 | 1282 | ||
1335 | ecodec: | 1283 | ecodec: |
@@ -1345,7 +1293,6 @@ ereqreg: | |||
1345 | erate: | 1293 | erate: |
1346 | clk_put(hdmi->hdmi_clk); | 1294 | clk_put(hdmi->hdmi_clk); |
1347 | egetclk: | 1295 | egetclk: |
1348 | mutex_destroy(&hdmi->mutex); | ||
1349 | kfree(hdmi); | 1296 | kfree(hdmi); |
1350 | 1297 | ||
1351 | return ret; | 1298 | return ret; |
@@ -1359,8 +1306,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) | |||
1359 | 1306 | ||
1360 | snd_soc_unregister_codec(&pdev->dev); | 1307 | snd_soc_unregister_codec(&pdev->dev); |
1361 | 1308 | ||
1362 | fb_unregister_client(&hdmi->notifier); | ||
1363 | |||
1364 | /* No new work will be scheduled, wait for running ISR */ | 1309 | /* No new work will be scheduled, wait for running ISR */ |
1365 | free_irq(irq, hdmi); | 1310 | free_irq(irq, hdmi); |
1366 | /* Wait for already scheduled work */ | 1311 | /* Wait for already scheduled work */ |
@@ -1371,7 +1316,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) | |||
1371 | clk_put(hdmi->hdmi_clk); | 1316 | clk_put(hdmi->hdmi_clk); |
1372 | iounmap(hdmi->base); | 1317 | iounmap(hdmi->base); |
1373 | release_mem_region(res->start, resource_size(res)); | 1318 | release_mem_region(res->start, resource_size(res)); |
1374 | mutex_destroy(&hdmi->mutex); | ||
1375 | kfree(hdmi); | 1319 | kfree(hdmi); |
1376 | 1320 | ||
1377 | return 0; | 1321 | return 0; |