+ for (i = 0; i< bg_ptr->pdata->sensor_count; i++)
+ configure_temp_sensor_counter(bg_ptr, i, 1);
+
+ for (i = 0; i< bg_ptr->pdata->sensor_count; i++) {
+ struct temp_sensor_data *ts_data;
+
+ ts_data = bg_ptr->pdata->sensors[i].ts_data;
+
+ temp_sensor_init_talert_thresholds(bg_ptr, i,
+ ts_data->t_hot,
+ ts_data->t_cold);
+ temp_sensor_configure_tshut_hot(bg_ptr, i,
+ ts_data->tshut_hot);
+ temp_sensor_configure_tshut_cold(bg_ptr, i,
+ ts_data->tshut_cold);
+ }
+
+ enable_continuous_mode(bg_ptr);
+
+ /* Set .250 seconds time as default counter */
+ for (i = 0; i< bg_ptr->pdata->sensor_count; i++)
+ configure_temp_sensor_counter(bg_ptr, i,
+ bg_ptr->clk_rate / 4);
+
+ /* Every thing is good? Then expose the sensors */
+ for (i = 0; i< bg_ptr->pdata->sensor_count; i++) {
+ char *domain;
+
+ domain = bg_ptr->pdata->sensors[i].domain;
+ if (bg_ptr->pdata->expose_sensor)
+ bg_ptr->pdata->expose_sensor(bg_ptr, i, domain);
+ }
+
+ return 0;
+
+put_clks:
+ clk_disable(bg_ptr->fclock);
+ clk_put(bg_ptr->fclock);
+ clk_put(bg_ptr->div_clk);
+free_irqs:
+ free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
+ gpio_free(bg_ptr->tshut_gpio);
+free_talert:
+ free_irq(bg_ptr->irq, bg_ptr);
+
+ return ret;
+}
+
+static
+int __devexit omap_bandgap_remove(struct platform_device *pdev)
+{
+ struct omap_bandgap *bg_ptr = platform_get_drvdata(pdev);
+
+ clk_disable(bg_ptr->fclock);
+ clk_put(bg_ptr->fclock);
+ clk_put(bg_ptr->div_clk);
+ free_irq(bg_ptr->irq, bg_ptr);
+ free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
+ gpio_free(bg_ptr->tshut_gpio);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_bandgap_save_ctxt(struct omap_bandgap *bg_ptr)
+{
+ struct device *cdev = bg_ptr->dev->parent;
+ int err = 0;
+ int i;
+
+ for (i = 0; i< bg_ptr->pdata->sensor_count; i++) {
+ struct temp_sensor_registers *tsr;
+ struct temp_sensor_regval *rval;
+
+ rval = bg_ptr->pdata->sensors[i].regval;
+ tsr = bg_ptr->pdata->sensors[i].registers;
+
+ err = omap_control_readl(cdev, tsr->bgap_mode_ctrl,
+ &rval->bg_mode_ctrl);
+ err |= omap_control_readl(cdev, tsr->bgap_mask_ctrl,
+ &rval->bg_ctrl);
+ err |= omap_control_readl(cdev, tsr->bgap_counter,
+ &rval->bg_counter);
+ err |= omap_control_readl(cdev, tsr->bgap_threshold,
+ &rval->bg_threshold);
+ err |= omap_control_readl(cdev, tsr->tshut_threshold,
+ &rval->tshut_threshold);
+
+ if (err)
+ dev_err(bg_ptr->dev, "could not save sensor %d\n", i);
+ }
+
+ return err ? -EIO : 0;
+}
+
+static int
+omap_bandgap_force_single_read(struct omap_bandgap *bg_ptr, int id)
+{
+ struct device *cdev = bg_ptr->dev->parent;
+ struct temp_sensor_registers *tsr;
+ u32 temp = 0, counter = 1000;
+ int err;
+
+ tsr = bg_ptr->pdata->sensors[id].registers;
+ /* Select single conversion mode */
+ err = omap_control_readl(cdev, tsr->bgap_mode_ctrl,&temp);
+ temp&= ~(1<< __ffs(tsr->mode_ctrl_mask));
+ omap_control_writel(cdev, temp, tsr->bgap_mode_ctrl);
+
+ /* Start of Conversion = 1 */
+ err |= omap_control_readl(cdev, tsr->temp_sensor_ctrl,&temp);
+ temp |= 1<< __ffs(tsr->bgap_soc_mask);
+ omap_control_writel(cdev, temp, tsr->temp_sensor_ctrl);
+ /* Wait until DTEMP is updated */
+ err |= omap_control_readl(cdev, tsr->temp_sensor_ctrl,&temp);
+ temp&= (tsr->bgap_dtemp_mask);
+ while ((temp == 0)&& --counter) {
+ err |= omap_control_readl(cdev, tsr->temp_sensor_ctrl,&temp);
+ temp&= (tsr->bgap_dtemp_mask);
+ }
+ /* Start of Conversion = 0 */
+ err |= omap_control_readl(cdev, tsr->temp_sensor_ctrl,&temp);
+ temp&= ~(1<< __ffs(tsr->bgap_soc_mask));
+ err |= omap_control_writel(cdev, temp, tsr->temp_sensor_ctrl);
+
+ return err ? -EIO : 0;
+}
+
+static int omap_bandgap_restore_ctxt(struct omap_bandgap *bg_ptr)
+{
+ struct device *cdev = bg_ptr->dev->parent;
+ int i, err = 0;
+ u32 temp = 0;
+
+ for (i = 0; i< bg_ptr->pdata->sensor_count; i++) {
+ struct temp_sensor_registers *tsr;
+ struct temp_sensor_regval *rval;
+ u32 val;
+
+ rval = bg_ptr->pdata->sensors[i].regval;
+ tsr = bg_ptr->pdata->sensors[i].registers;
+
+ err = omap_control_readl(cdev, tsr->bgap_counter,&val);
+ if (val == 0) {
+ err |= omap_control_writel(cdev, rval->bg_threshold,
+ tsr->bgap_threshold);
+ err |= omap_control_writel(cdev, rval->tshut_threshold,
+ tsr->tshut_threshold);
+ /* Force immediate temperature measurement and update
+ * of the DTEMP field
+ */
+ omap_bandgap_force_single_read(bg_ptr, i);
+ err |= omap_control_writel(cdev, rval->bg_counter,
+ tsr->bgap_counter);
+ err |= omap_control_writel(cdev, rval->bg_mode_ctrl,
+ tsr->bgap_mode_ctrl);
+ err |= omap_control_writel(cdev, rval->bg_ctrl,
+ tsr->bgap_mask_ctrl);
+ } else {
+ err |= omap_control_readl(cdev, tsr->temp_sensor_ctrl,
+ &temp);
+ temp&= (tsr->bgap_dtemp_mask);
+ if (temp == 0) {
+ omap_bandgap_force_single_read(bg_ptr, i);
+ err |= omap_control_readl(cdev,
+ tsr->bgap_mask_ctrl,
+ &temp);
+ temp |= 1<< __ffs(tsr->mode_ctrl_mask);
+ err |= omap_control_writel(cdev, temp,
+ tsr->bgap_mask_ctrl);
+ }
+ }
+ if (err)
+ dev_err(bg_ptr->dev, "could not save sensor %d\n", i);
+ }
+
+ return err ? -EIO : 0;
+}
+
+static int omap_bandgap_suspend(struct device *dev)
+{
+ struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
+ int err;
+
+ err = omap_bandgap_save_ctxt(bg_ptr);
+ clk_disable(bg_ptr->fclock);
+
+ return err;
+}
+
+static int omap_bandgap_resume(struct device *dev)
+{
+ struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
+
+ clk_enable(bg_ptr->fclock);
+
+ return omap_bandgap_restore_ctxt(bg_ptr);
+}
+static const struct dev_pm_ops omap_bandgap_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(omap_bandgap_suspend,
+ omap_bandgap_resume)
+};
+
+#define DEV_PM_OPS (&omap_bandgap_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver omap_bandgap_sensor_driver = {
+ .probe = omap_bandgap_probe,
+ .remove = omap_bandgap_remove,
+ .driver = {
+ .name = "omap-bandgap",
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_omap_bandgap_match,
+ },
+};
+
+module_platform_driver(omap_bandgap_sensor_driver);
+early_platform_init("early_omap_temperature",&omap_bandgap_sensor_driver);
+
+MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:omap-bandgap");
+MODULE_AUTHOR("Texas Instrument Inc.");
diff --git a/drivers/thermal/omap-bandgap.h b/drivers/thermal/omap-bandgap.h
new file mode 100644
index 0000000..12e0d6b
--- /dev/null
+++ b/drivers/thermal/omap-bandgap.h
@@ -0,0 +1,63 @@
+/*
+ * OMAP4 Bandgap temperature sensor driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin<eduardo.valentin@xxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __OMAP_BANDGAP_H
+#define __OMAP_BANDGAP_H
+
+struct omap_bandgap_data;
+
+/**
+ * struct omap_bandgap - bandgap device structure
+ * @dev: device pointer
+ * @pdata: platform data with sensor data
+ * @fclock: pointer to functional clock of temperature sensor
+ * @div_clk: pointer to parent clock of temperature sensor fclk
+ * @conv_table: Pointer to adc to temperature conversion table
+ * @bg_mutex: Mutex for sysfs, irq and PM
+ * @irq: MPU Irq number for thermal alert
+ * @tshut_gpio: GPIO where Tshut signal is routed
+ * @clk_rate: Holds current clock rate
+ */
+struct omap_bandgap {
+ struct device *dev;
+ const struct omap_bandgap_data *pdata;
+ struct clk *fclock;
+ struct clk *div_clk;
+ const int *conv_table;
+ struct mutex bg_mutex; /* Mutex for irq and PM */
+ int irq;
+ int tshut_gpio;
+ u32 clk_rate;
+};
+
+int omap_bandgap_read_thot(struct omap_bandgap *bg_ptr, int id, int *thot);
+int omap_bandgap_write_thot(struct omap_bandgap *bg_ptr, int id, int val);
+int omap_bandgap_read_tcold(struct omap_bandgap *bg_ptr, int id, int *tcold);
+int omap_bandgap_write_tcold(struct omap_bandgap *bg_ptr, int id, int val);
+int omap_bandgap_read_update_interval(struct omap_bandgap *bg_ptr, int id,
+ int *interval);
+int omap_bandgap_write_update_interval(struct omap_bandgap *bg_ptr, int id,
+ u32 interval);
+int omap_bandgap_read_temperature(struct omap_bandgap *bg_ptr, int id,
+ int *temperature);
+
+#endif