@@ -30,6 +30,7 @@
#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <plat/display.h>
@@ -68,6 +69,73 @@ static irqreturn_t taal_te_isr(int irq, void *data);
static void taal_te_timeout_work_callback(struct work_struct *work);
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
+struct panel_regulator {
+ struct regulator *regulator;
+ const char *name;
+ int min_uV;
+ int max_uV;
+};
+
+static void free_regulators(struct panel_regulator *regulators, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ /* disable/put in reverse order */
+ regulator_disable(regulators[n - i - 1].regulator);
+ regulator_put(regulators[n - i - 1].regulator);
+ }
+}
+
+static int init_regulators(struct omap_dss_device *dssdev,
+ struct panel_regulator *regulators, int n)
+{
+ int r, i, v;
+
+ for (i = 0; i < n; i++) {
+ struct regulator *reg;
+
+ reg = regulator_get(&dssdev->dev, regulators[i].name);
+ if (IS_ERR(reg)) {
+ dev_err(&dssdev->dev, "failed to get regulator %s\n",
+ regulators[i].name);
+ r = PTR_ERR(reg);
+ goto err;
+ }
+
+ /* FIXME: better handling of fixed vs. variable regulators */
+ v = regulator_get_voltage(reg);
+ if (v < regulators[i].min_uV || v > regulators[i].max_uV) {
+ r = regulator_set_voltage(reg, regulators[i].min_uV,
+ regulators[i].max_uV);
+ if (r) {
+ dev_err(&dssdev->dev,
+ "failed to set regulator %s voltage\n",
+ regulators[i].name);
+ regulator_put(reg);
+ goto err;
+ }
+ }
+
+ r = regulator_enable(reg);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to enable regulator %s\n",
+ regulators[i].name);
+ regulator_put(reg);
+ goto err;
+ }
+
+ regulators[i].regulator = reg;
+ }
+
+ return 0;
+
+err:
+ free_regulators(regulators, i);
+
+ return r;
+}
+
/**
* struct panel_config - panel configuration
* @name: panel name
@@ -75,6 +143,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
* @timings: panel resolution
* @sleep: various panel specific delays, passed to msleep() if non-zero
* @reset_sequence: reset sequence timings, passed to udelay() if non-zero
+ * @regulators: array of panel regulators
+ * @num_regulators: number of regulators in the array
*/
struct panel_config {
const char *name;
@@ -93,6 +163,9 @@ struct panel_config {
unsigned int high;
unsigned int low;
} reset_sequence;
+
+ struct panel_regulator *regulators;
+ int num_regulators;
};
enum {
@@ -629,6 +702,11 @@ static int taal_probe(struct omap_dss_device *dssdev)
atomic_set(&td->do_update, 0);
+ r = init_regulators(dssdev, panel_config->regulators,
+ panel_config->num_regulators);
+ if (r)
+ goto err_reg;
+
td->esd_wq = create_singlethread_workqueue("taal_esd");
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
@@ -715,6 +793,8 @@ err_gpio:
err_bl:
destroy_workqueue(td->esd_wq);
err_wq:
+ free_regulators(panel_config->regulators, panel_config->num_regulators);
+err_reg:
kfree(td);
err:
return r;
@@ -747,6 +827,9 @@ static void taal_remove(struct omap_dss_device *dssdev)
/* reset, to be sure that the panel is in a valid state */
taal_hw_reset(dssdev);
+ free_regulators(td->panel_config->regulators,
+ td->panel_config->num_regulators);
+
kfree(td);
}