return 0;
 }
 
+static bool clocksource_is_watchdog(struct clocksource *cs)
+{
+       return cs == watchdog;
+}
+
 #else /* CONFIG_CLOCKSOURCE_WATCHDOG */
 
 static void clocksource_enqueue_watchdog(struct clocksource *cs)
 static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
 static inline void clocksource_resume_watchdog(void) { }
 static inline int clocksource_watchdog_kthread(void *data) { return 0; }
+static bool clocksource_is_watchdog(struct clocksource *cs) { return false; }
 
 #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
 
        return __clocksource_select(false);
 }
 
+static void clocksource_select_fallback(void)
+{
+       return __clocksource_select(true);
+}
+
 #else /* !CONFIG_ARCH_USES_GETTIMEOFFSET */
 
 static inline void clocksource_select(void) { }
 }
 EXPORT_SYMBOL(clocksource_change_rating);
 
+/*
+ * Unbind clocksource @cs. Called with clocksource_mutex held
+ */
+static int clocksource_unbind(struct clocksource *cs)
+{
+       /*
+        * I really can't convince myself to support this on hardware
+        * designed by lobotomized monkeys.
+        */
+       if (clocksource_is_watchdog(cs))
+               return -EBUSY;
+
+       if (cs == curr_clocksource) {
+               /* Select and try to install a replacement clock source */
+               clocksource_select_fallback();
+               if (curr_clocksource == cs)
+                       return -EBUSY;
+       }
+       clocksource_dequeue_watchdog(cs);
+       list_del_init(&cs->list);
+       return 0;
+}
+
 /**
  * clocksource_unregister - remove a registered clocksource
  * @cs:        clocksource to be unregistered
        return ret;
 }
 
+/**
+ * sysfs_unbind_current_clocksource - interface for manually unbinding clocksource
+ * @dev:       unused
+ * @attr:      unused
+ * @buf:       unused
+ * @count:     length of buffer
+ *
+ * Takes input from sysfs interface for manually unbinding a clocksource.
+ */
+static ssize_t sysfs_unbind_clocksource(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct clocksource *cs;
+       char name[CS_NAME_LEN];
+       size_t ret;
+
+       ret = clocksource_get_uname(buf, name, count);
+       if (ret < 0)
+               return ret;
+
+       ret = -ENODEV;
+       mutex_lock(&clocksource_mutex);
+       list_for_each_entry(cs, &clocksource_list, list) {
+               if (strcmp(cs->name, name))
+                       continue;
+               ret = clocksource_unbind(cs);
+               break;
+       }
+       mutex_unlock(&clocksource_mutex);
+
+       return ret ? ret : count;
+}
+
 /**
  * sysfs_show_available_clocksources - sysfs interface for listing clocksource
  * @dev:       unused
 static DEVICE_ATTR(current_clocksource, 0644, sysfs_show_current_clocksources,
                   sysfs_override_clocksource);
 
+static DEVICE_ATTR(unbind_clocksource, 0200, NULL, sysfs_unbind_clocksource);
+
 static DEVICE_ATTR(available_clocksource, 0444,
                   sysfs_show_available_clocksources, NULL);
 
                error = device_create_file(
                                &device_clocksource,
                                &dev_attr_current_clocksource);
+       if (!error)
+               error = device_create_file(&device_clocksource,
+                                          &dev_attr_unbind_clocksource);
        if (!error)
                error = device_create_file(
                                &device_clocksource,