aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-09-18 06:25:21 -0400
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-03-12 17:40:51 -0400
commitbce95fe838a5ca84e57411338b953be672c2a5eb (patch)
treeab99cb3ef78de9677b83c45e27e2372fa4cc3d6b /drivers
parente34d0bbb062cc78802d0f0686c939ea1569889a6 (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.c80
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
233static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) 229static 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,
737static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, 733static 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 */
1044static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) 1037static 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
1058static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) 1051static 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,
1121static void sh_hdmi_edid_work_fn(struct work_struct *work) 1113static 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)
1200out: 1190out:
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
1208static 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
1244static int __init sh_hdmi_probe(struct platform_device *pdev) 1197static 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
1335ecodec: 1283ecodec:
@@ -1345,7 +1293,6 @@ ereqreg:
1345erate: 1293erate:
1346 clk_put(hdmi->hdmi_clk); 1294 clk_put(hdmi->hdmi_clk);
1347egetclk: 1295egetclk:
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;