WindCharger: implements hwmon driver for lm95071 device.

Change-Id: I7e4ab00b0d64f07797514555e09fd95cd19d52de
diff --git a/arch/mips/configs/gfwc100_defconfig b/arch/mips/configs/gfwc100_defconfig
old mode 100755
new mode 100644
index 3501c13..3ee0e82
--- a/arch/mips/configs/gfwc100_defconfig
+++ b/arch/mips/configs/gfwc100_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.31
-# Wed Mar 25 14:49:02 2015
+# Thu Apr  9 15:45:38 2015
 #
 CONFIG_MIPS=y
 
@@ -367,6 +367,12 @@
 # CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
 CONFIG_IPV6=y
@@ -662,6 +668,8 @@
 # CFG80211 needs to be enabled for MAC80211
 #
 CONFIG_MAC80211_DEFAULT_PS_VALUE=0
+# CONFIG_MAC80211_RC_DEFAULT_PID is not set
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -975,7 +983,24 @@
 # CONFIG_PPS is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+CONFIG_SENSORS_LM95071_ATH_MN=y
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
@@ -1020,6 +1045,36 @@
 # Special HID drivers
 #
 # CONFIG_USB_SUPPORT is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_AR9130 is not set
+# CONFIG_USB_GADGET_ATH is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
 # CONFIG_UWB is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -1108,6 +1163,10 @@
 # CONFIG_JFFS2_LZMA is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
 # CONFIG_CRAMFS is not set
 CONFIG_SQUASHFS=y
 # CONFIG_SQUASHFS_LZMA is not set
@@ -1119,6 +1178,9 @@
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_ROMFS_FS is not set
+# CONFIG_ROMFS_BACKED_BY_BLOCK is not set
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_NILFS2_FS is not set
@@ -1188,6 +1250,9 @@
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_TRACING_SUPPORT=y
 # CONFIG_FTRACE is not set
+# CONFIG_BRANCH_PROFILE_NONE is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_SAMPLES is not set
 # CONFIG_HAVE_ARCH_KGDB is not set
 CONFIG_CMDLINE="console=ttyS0,115200 root=01:00 rd_start=0x802d0000 rd_size=0x800000 init=/sbin/init mem=32m mtdparts=ath-nor0:256k(u-boot),64k(u-boot-env),6336k(rootfs),1408k(uImage),64k(mib0),64k(ART)"
diff --git a/arch/mips/include/asm/mach-atheros/atheros.h b/arch/mips/include/asm/mach-atheros/atheros.h
index 1eecc44..044be22 100755
--- a/arch/mips/include/asm/mach-atheros/atheros.h
+++ b/arch/mips/include/asm/mach-atheros/atheros.h
@@ -253,39 +253,21 @@
  *
  *****************************************************************************/
 
-#define ATH_MN_TEMP_SENSOR_PIN (1 << 14)
-
-/* Enables flash CS. Blocking for mutual exclusion GPIO on pin 14. */
+/*
+ * Enables CS.  Blocking for mutual exclusion GPIO 14/5
+ * (depending on the caller).
+ */
 static inline void
-ath_mn_spi_enable_flash_cs(void)
+ath_mn_spi_enable_cs(void)
 {
   ath_spi_down();
   ath_spi_enable_soft_access();
-  /*
-   * Only handles the temp sensor pin, as the flash driver deals with GPIO pin 5
-   * on its own.
-   */
-  ath_gpio_drive_high(ATH_MN_TEMP_SENSOR_PIN);
-}
-
-/* Enables LM sensor CS pin.  Blocking for mutual exclusion GPIO on pin 14. */
-static inline void
-ath_mn_spi_enable_lm_cs(void)
-{
-  ath_spi_down();
-  ath_spi_enable_soft_access();
-  /*
-   * Only handles the temp sensor pin, as the flash driver deals with GPIO pin 5
-   * on its own.
-   */
-  ath_gpio_drive_low(ATH_MN_TEMP_SENSOR_PIN);  /* Enables temp sensor pin. */
 }
 
 /* Releases chipselect. */
 static inline void
 ath_mn_spi_disable_cs(void)
 {
-  ath_gpio_drive_high(ATH_MN_TEMP_SENSOR_PIN);
   ath_spi_disable_soft_access();
   ath_spi_up();
 }
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d50166..2d61d55 100755
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -593,6 +593,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm93.
 
+config SENSORS_LM95071_ATH_MN
+	tristate "National Semiconductor LM95071"
+	depends on HWMON && EXPERIMENTAL
+	help
+	  If you say yes here you get support for National Semiconductor LM95071
+	  sensor chip, as handled for the Atheros GFMN device.  This will not work
+	  otherwise.
+
+	  You have been warned.  If you don't know what you're doing, do not select
+	  this option.
+
 config SENSORS_LTC4215
 	tristate "Linear Technology LTC4215"
 	depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b793dce..2dbef4c 100755
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -68,6 +68,7 @@
 obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 obj-$(CONFIG_SENSORS_LM93)	+= lm93.o
 obj-$(CONFIG_SENSORS_LM95241)	+= lm95241.o
+obj-$(CONFIG_SENSORS_LM95071_ATH_MN)	+= ath_mn_lm95071.o
 obj-$(CONFIG_SENSORS_LTC4215)	+= ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)	+= ltc4245.o
 obj-$(CONFIG_SENSORS_MAX1111)	+= max1111.o
diff --git a/drivers/hwmon/ath_mn_lm95071.c b/drivers/hwmon/ath_mn_lm95071.c
new file mode 100644
index 0000000..8a7d102
--- /dev/null
+++ b/drivers/hwmon/ath_mn_lm95071.c
@@ -0,0 +1,155 @@
+/**
+ * SPI Driver for LM95071 temperature sensor device.  This is implemented
+ * specifically in the context of the Atheros 953x GFMN board, and not meant to
+ * be a general solution (a more robust solution would likely be implemented
+ * using a parport interface).
+ *
+ * The LM95071 temperature sensor uses a 3-pin SPI interface.  On this board,
+ * the device shares the MISO and CLK pins with the flash device.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/spi/spi.h>
+#include <asm/delay.h>
+#include <atheros.h>
+
+#include "ath_mn_lm95071.h"
+
+#define DRVNAME "lm95071"
+
+struct lm95071 {
+  struct device *dev;
+  void (*lock)(void);
+  void (*unlock)(void);
+};
+
+static void lm_lock(void) {
+  ath_mn_spi_enable_cs();
+  lm_spi_func_clear();
+  ath_gpio_drive_low(ATH_MN_TEMP_SENSOR_PIN);
+  lm_delay();
+}
+
+static void lm_unlock(void) {
+  ath_gpio_drive_high(ATH_MN_TEMP_SENSOR_PIN);
+  lm_spi_func_restore();
+  ath_mn_spi_disable_cs();
+}
+
+static struct lm95071 lm_dev = {
+  .dev         = NULL,
+  .lock        = lm_lock,
+  .unlock      = lm_unlock,
+};
+
+/* Enables continuous conversion mode. */
+static void lm95071_enable_cc(void)
+{
+  lm_dev.lock();
+  lm_spi_delay_16();
+  lm_spi_delay_8();
+  lm_spi_bit_banger(LM_MODE_CC);
+  lm_dev.unlock();
+}
+
+static int lm95071_detect(void)
+{
+  /* TODO(awdavies) Implement this function to read the ID register. */
+  return 0;
+}
+
+static ssize_t lm95071_get_temperature(struct device *dev,
+                                       struct device_attribute *attr, char *buf)
+{
+  s16 temp;
+  u16 raw_temp, sign;
+  int is_negative = 1;
+  lm_dev.lock();
+  lm_spi_delay_16();
+  raw_temp = lm_spi_rd_16();
+  lm_dev.unlock();
+  sign = 0x8000 & raw_temp;
+  if (sign) {
+    raw_temp = ~raw_temp + 1;
+  }
+  temp = raw_temp >> 7;
+
+  /*
+   * LM90571 Temp register has two unused bits at the end.  After these are
+   * removed, every number remaining corresponds to 0.03125 C of temperature.
+   *
+   * Official docs here: http://www.ti.com/lit/ds/symlink/lm95071.pdf
+   */
+  return sprintf(buf, "%d\n", sign ? -temp : temp);
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, lm95071_get_temperature, NULL);
+
+static ssize_t lm95071_get_name(struct device *dev,
+                                struct device_attribute *devattr, char *buf)
+{
+  return sprintf(buf, "%s\n", DRVNAME);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, lm95071_get_name, NULL);
+
+static int lm95071_probe(void)
+{
+  int res;
+  if (lm95071_detect()) {
+    printk(KERN_NOTICE "hwmon_dev_detect failed (lm95071)\n");
+    res = -ENOENT;
+    goto dev_detect_failed;
+  }
+  lm95071_enable_cc();
+  lm_dev.dev = hwmon_device_register(NULL);
+  if (IS_ERR(lm_dev.dev)) {
+    printk(KERN_NOTICE "%x hwmon_dev_reg failed (lm95071)\n", lm_dev.dev);
+    res = PTR_ERR(lm_dev.dev);
+    goto dev_reg_failed;
+  }
+  dev_set_drvdata(lm_dev.dev, &lm_dev);
+  /* Here is where sysfs gets hooked. */
+  if ((res = device_create_file(lm_dev.dev, &dev_attr_temp1_input))
+      || (res = device_create_file(lm_dev.dev, &dev_attr_name))) {
+    printk(KERN_NOTICE "hwmon_dev_create failed (lm95071)\n");
+    goto dev_create_failed;
+  }
+  /* Sanity check. */
+  printk(KERN_NOTICE "lm95071 temp sensor driver initialized.\n");
+  return 0;
+
+dev_create_failed:
+  device_remove_file(lm_dev.dev, &dev_attr_temp1_input);
+  hwmon_device_unregister(lm_dev.dev);
+dev_reg_failed:
+  dev_set_drvdata(lm_dev.dev, NULL);
+dev_detect_failed:
+  return res;
+}
+
+static void lm95071_remove(void)
+{
+  device_remove_file(lm_dev.dev, &dev_attr_temp1_input);
+  device_remove_file(lm_dev.dev, &dev_attr_name);
+  hwmon_device_unregister(lm_dev.dev);
+  dev_set_drvdata(lm_dev.dev, NULL);
+}
+
+static int __init init_lm95071(void)
+{
+  return lm95071_probe();
+}
+
+static void __exit cleanup_lm95071(void)
+{
+  lm95071_remove();
+}
+
+module_init(init_lm95071);
+module_exit(cleanup_lm95071);
diff --git a/drivers/hwmon/ath_mn_lm95071.h b/drivers/hwmon/ath_mn_lm95071.h
new file mode 100644
index 0000000..62108e1
--- /dev/null
+++ b/drivers/hwmon/ath_mn_lm95071.h
@@ -0,0 +1,52 @@
+#ifndef __ATH_MN_LM95071_H__
+#define __ATH_MN_LM95071_H__
+
+#define ATH_MN_TEMP_SENSOR_PIN (1 << 14)
+#define ATH_SPI_CE_LOW  0x60000
+#define ATH_SPI_CE_HIGH 0x60100
+#define ATH_SPI_SC_UDELAY 200
+#define ATH_MUX_SPI_CS_0 0x9  /* SPI_CS_0 signal on QCA mux. */
+
+#define LM_MODE_SD 0xFF  /* shutdown mode */
+#define LM_MODE_CC 0x00  /* continuous conversion */
+
+#define lm_delay() udelay(ATH_SPI_SC_UDELAY)
+
+#define lm_be_msb(_val, __i) (((_val) & (1 << (7 - __i))) >> (7 - __i))
+
+#define lm_spi_bit_banger(_byte) do { \
+  int _i; \
+  for (_i = 0; _i < 8; ++_i) { \
+    ath_reg_wr_nf(ATH_SPI_WRITE, ATH_SPI_CE_HIGH | lm_be_msb(_byte, _i)); \
+    lm_delay(); \
+    ath_reg_wr_nf(ATH_SPI_WRITE, ATH_SPI_CE_LOW | lm_be_msb(_byte, _i)); \
+    lm_delay(); \
+  } \
+} while (0)
+
+/*
+ * Clears out signals on GPIO pins 14/5.
+ */
+#define lm_spi_func_clear() do { \
+  ath_reg_rmw_clear(ATH_GPIO_OUT_FUNCTION1, GPIO_OUT_FUNCTION0_ENABLE_GPIO_1_MASK); \
+  ath_reg_rmw_clear(ATH_GPIO_OUT_FUNCTION3, GPIO_OUT_FUNCTION3_ENABLE_GPIO_14_MASK); \
+} while (0)
+
+/* Reenables GPIO pin 5 to functions as CS_0 signal. */
+#define lm_spi_func_restore() do { \
+  ath_reg_rmw_set(ATH_GPIO_OUT_FUNCTION1, \
+                  ATH_GPIO_OUT_FUNCTION1_ENABLE_GPIO_5(ATH_MUX_SPI_CS_0)); \
+} while (0)
+
+#define lm_spi_delay_8() lm_spi_bit_banger(0)
+
+#define lm_spi_delay_16() do { \
+  lm_spi_delay_8(); \
+  lm_spi_delay_8(); \
+} while (0);
+
+#define lm_spi_rd_16() (ath_reg_rd(ATH_SPI_RD_STATUS) & 0xFFFF)
+
+#define lm_temp_rd() ((lm_spi_rd_16()) / 4 * 3125)
+
+#endif  // __ATH_MN_LM95071_H__
diff --git a/drivers/mtd/devices/ath_flash.c b/drivers/mtd/devices/ath_flash.c
index 5936f1b..8f088b8 100755
--- a/drivers/mtd/devices/ath_flash.c
+++ b/drivers/mtd/devices/ath_flash.c
@@ -104,7 +104,7 @@
 	if (instr->addr + instr->len > mtd->size)
 		return (-EINVAL);
 
-	ath_mn_spi_enable_flash_cs();
+	ath_mn_spi_enable_cs();
 
 	res = instr->len;
 	do_div(res, mtd->erasesize);
@@ -147,7 +147,7 @@
 		return (-EINVAL);
 	}
 
-	ath_mn_spi_enable_flash_cs();
+	ath_mn_spi_enable_cs();
 
 	ath_spi_write_enable();
 	ath_spi_bit_banger(ATH_SPI_CMD_READ);
@@ -209,7 +209,7 @@
 	uint32_t addr = 0;
 	u_char *mem;
 
-	ath_mn_spi_enable_flash_cs();
+	ath_mn_spi_enable_cs();
 
 	while (total < len) {
 		mem = (u_char *) (buf + total);
@@ -488,7 +488,7 @@
 	uint32_t ori_ear = (uint32_t)ath_spi_rdear();
 	uint32_t new_ear;
 
-	ath_mn_spi_enable_flash_cs();
+	ath_mn_spi_enable_cs();
 	while (i < len) {
 		new_ear = curr_addr >> 24;
 		ath_spi_wrear(new_ear);
@@ -524,7 +524,7 @@
 	uint32_t bytes_this_16M, total = 0;
 	*retlen = len;
 
-	ath_mn_spi_enable_flash_cs();
+	ath_mn_spi_enable_cs();
 	while (len) {
 		size_t tmp;
 		new_ear = curr_addr >> 24;