diff --git a/plugins/mtpdevice/rb-mtp-source.c b/plugins/mtpdevice/rb-mtp-source.c
index 4879929..edb3bcc 100644
--- a/plugins/mtpdevice/rb-mtp-source.c
+++ b/plugins/mtpdevice/rb-mtp-source.c
@@ -114,6 +114,19 @@ static void prepare_encoder_sink_cb (RBEncoderFactory *factory,
 				     GObject *sink,
 				     RBMtpSource *source);
 
+static void rb_mtp_source_load_playlists (RBMtpSource *source);
+static void rb_mtp_source_add_playlist (RBMtpSource *source, LIBMTP_playlist_t *playlist);
+static void playlist_track_removed (GtkTreeModel *model, GtkTreePath *path, 
+                               RhythmDBQueryModel *query, gpointer data);
+static void playlist_track_added (GtkTreeModel *model, GtkTreePath *path,
+                     GtkTreeIter *iter, gpointer data);
+static void update_mtp_playlist (GtkTreeModel *model, RBStaticPlaylistSource *playlist);
+static gboolean add_playlist_entry_to_mtp_playlist (GtkTreeModel *model, GtkTreePath *path,
+                                               GtkTreeIter *iter, gpointer list);
+static gboolean mtp_playlist_from_playlist_source (GtkTreeModel *model,
+                                               RBStaticPlaylistSource *playlist,
+                                               RBMtpSource *source);
+
 typedef struct
 {
 	RBMtpThread *device_thread;
@@ -136,6 +149,8 @@ typedef struct
 	guint64 capacity;
 	guint64 free_space;		/* updated by callbacks */
 
+	GList *playlists;
+	LIBMTP_playlist_t *device_playlists;
 } RBMtpSourcePrivate;
 
 RB_PLUGIN_DEFINE_TYPE(RBMtpSource,
@@ -773,6 +788,8 @@ mtp_device_open_cb (LIBMTP_mtpdevice_t *device, RBMtpSource *source)
 
 	/* now get the track list */
 	rb_mtp_thread_get_track_list (priv->device_thread, (RBMtpTrackListCallback) mtp_tracklist_cb, g_object_ref (source), g_object_unref);
+
+	rb_mtp_source_load_playlists (source);
 }
 
 static void
@@ -1299,3 +1316,183 @@ prepare_encoder_source_cb (RBEncoderFactory *factory,
 	prepare_source (source, stream_uri, src);
 }
 
+static void
+playlist_track_added (GtkTreeModel *model, GtkTreePath *path,
+                     GtkTreeIter *iter, gpointer data)
+{
+	RBStaticPlaylistSource *playlist = RB_STATIC_PLAYLIST_SOURCE (data);
+	update_mtp_playlist (model, playlist);
+}
+
+static void
+playlist_track_removed (GtkTreeModel *model, GtkTreePath *path, 
+                               RhythmDBQueryModel *query, gpointer data)
+{
+	RBStaticPlaylistSource *playlist = RB_STATIC_PLAYLIST_SOURCE (data);
+	update_mtp_playlist (model, playlist);
+}
+
+static void
+update_mtp_playlist (GtkTreeModel *model, RBStaticPlaylistSource *playlist)
+{
+	RBMtpSource *source = g_object_get_data (G_OBJECT (playlist), "mtp-source");
+
+	if (!mtp_playlist_from_playlist_source (model, playlist, source)) {
+		rb_debug ("Failed to save playlist to device");
+	}
+
+	g_object_unref (model);
+}
+
+static void
+rb_mtp_source_load_playlists (RBMtpSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	LIBMTP_playlist_t *pl;
+
+	pl = LIBMTP_Get_Playlist_List (priv->device);
+	priv->device_playlists = pl;
+	while (pl != NULL) {
+		rb_debug("mtp-playlist: %s", pl->name);
+		rb_mtp_source_add_playlist (source, pl);
+		pl = pl->next;
+	}
+}
+
+static void
+rb_mtp_source_add_playlist (RBMtpSource *source, LIBMTP_playlist_t *playlist)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	RBShell *shell;
+	RhythmDB *db = get_db_for_source (source);
+	RBSource *playlist_source;
+	RhythmDBEntry *entry;
+	RhythmDBEntryType entry_type;
+	uint32_t i;
+	RhythmDBQueryModel *model;
+
+	g_object_get (source, "shell", &shell, "entry-type", &entry_type, NULL);
+
+	playlist_source = rb_static_playlist_source_new (shell,
+							 playlist->name,
+							 NULL,
+							 FALSE,
+							 entry_type);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	for (i = 0; i < playlist->no_tracks; i++) {
+		LIBMTP_track_t *track;
+		char *loc;
+
+		track = LIBMTP_Get_Trackmetadata(priv->device,
+						 playlist->tracks[i]);
+		loc = g_strdup_printf ("rb-mtp-%i", track->item_id);
+		rb_debug ("track location: %s", loc);
+		if (track != NULL) {
+			entry = rhythmdb_entry_lookup_by_location (db, loc);
+			if (entry) {
+				rb_static_playlist_source_add_entry (
+								     RB_STATIC_PLAYLIST_SOURCE (playlist_source),
+								     entry,
+								     -1);
+			}
+		} else {
+			rb_debug ("Invalid track");
+		}
+	}
+	g_object_unref (db);
+
+	model = rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (playlist_source));
+	g_signal_connect (model, "row-inserted",
+			  G_CALLBACK (playlist_track_added),
+			  playlist_source);
+	g_signal_connect (model, "row-deleted",
+			  G_CALLBACK (playlist_track_removed),
+			  playlist_source);
+
+	g_object_set_data (G_OBJECT (playlist_source),
+			   "mtp-source", source);
+	g_object_set_data (G_OBJECT (playlist_source),
+			   "mtp-playlist", playlist);
+
+	g_object_ref (G_OBJECT(playlist_source));
+	priv->playlists = g_list_prepend (priv->playlists, playlist_source);
+
+	if (playlist_source != NULL) {
+		rb_shell_append_source (shell, playlist_source, RB_SOURCE (source));
+	}
+
+	g_object_unref (shell);
+}
+
+static gboolean
+mtp_playlist_from_playlist_source (GtkTreeModel *model,
+				   RBStaticPlaylistSource *playlist,
+				   RBMtpSource *source)
+{
+	LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
+	LIBMTP_playlist_t *oldlist;
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	GList *ids = NULL, *tmp = NULL;
+
+	g_object_get (G_OBJECT (playlist), "name", &pl->name, NULL);
+
+	oldlist = g_object_get_data (G_OBJECT (playlist), "mtp-playlist");
+
+	pl->playlist_id = oldlist->playlist_id;
+
+	rb_debug ("Updating mtp playlist from source %s with id %d", pl->name, pl->playlist_id);
+
+	gtk_tree_model_foreach (GTK_TREE_MODEL (model),
+				(GtkTreeModelForeachFunc) add_playlist_entry_to_mtp_playlist,
+				&ids);
+
+	if (ids == NULL) {
+		return FALSE;
+	}
+
+	rb_debug ("GList length %d", g_list_length(ids));
+	if (g_list_length (ids) < 1) {
+		return FALSE;
+	}
+	pl->no_tracks = (uint32_t) g_list_length (ids);
+	pl->tracks = (uint32_t *) malloc (sizeof (uint32_t) * pl->no_tracks);
+	int i = 0;
+	for (tmp = g_list_first (ids); tmp != NULL; tmp = tmp->next, i++) {
+		pl->tracks[i] = (uint32_t) GPOINTER_TO_INT (tmp->data);
+	}
+
+	pl->next = oldlist->next;
+
+	if (LIBMTP_Update_Playlist (priv->device, pl) != 0) {
+		rb_debug ("Couldn't update playlist");
+		LIBMTP_Dump_Errorstack(priv->device);
+		LIBMTP_Clear_Errorstack(priv->device);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+add_playlist_entry_to_mtp_playlist (GtkTreeModel *model,
+				    GtkTreePath *path,
+				    GtkTreeIter *iter,
+				    gpointer list)
+{
+	RhythmDBEntry *entry = NULL;
+	GList **tracks;
+	tracks = (GList **) list;
+
+	gtk_tree_model_get (model, iter, 0, &entry, -1);
+	if (entry == NULL) {
+		return TRUE;
+	}
+
+	if (g_str_has_prefix (rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION), "rb-mtp-")) {
+		char *num = strrchr(rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION), '-') + 1;
+		uint32_t track_id = (uint32_t) g_ascii_strtod(num, NULL);
+		*tracks = g_list_append (*tracks, GINT_TO_POINTER(track_id));
+	}
+	return FALSE;
+}
+
