[ARM] tegra: stingray: Add SPI board file
authorRebecca Schultz Zavin <rebecca@android.com>
Thu, 27 May 2010 19:18:57 +0000 (12:18 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:32:59 +0000 (16:32 -0700)
Initial submission of Stingray SPI board file.

Change-Id: Iab0968bff87bde4acaf9a46f3a35ec3e39243634
Signed-off-by: Greg Meiste <w30289@motorola.com>
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/board-stingray-spi.c [new file with mode: 0644]
arch/arm/mach-tegra/board-stingray.c
arch/arm/mach-tegra/board-stingray.h

index 30bdad11f216efc1a39f398f4e4d2880aab73524..88218081d66dd94f78eedfbb6723c623c52e07e3 100644 (file)
@@ -59,3 +59,4 @@ obj-${CONFIG_MACH_STINGRAY}             += board-stingray-wifi.o
 obj-${CONFIG_MACH_STINGRAY}             += board-stingray-sensors.o
 obj-${CONFIG_MACH_STINGRAY}             += board-stingray-wlan_nvs.o
 obj-${CONFIG_MACH_STINGRAY}             += board-stingray-touch.o
+obj-${CONFIG_MACH_STINGRAY}             += board-stingray-spi.o
diff --git a/arch/arm/mach-tegra/board-stingray-spi.c b/arch/arm/mach-tegra/board-stingray-spi.c
new file mode 100644 (file)
index 0000000..fe26d5f
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2010 Motorola, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/spi/cpcap.h>
+#include <linux/spi/cpcap-regbits.h>
+#include <linux/spi/spi.h>
+
+#include <mach/irqs.h>
+
+#include "gpio-names.h"
+
+static struct cpcap_device *cpcap_di;
+
+static int cpcap_validity_reboot(struct notifier_block *this,
+                                unsigned long code, void *cmd)
+{
+       int ret = -1;
+       int result = NOTIFY_DONE;
+       char *mode = cmd;
+
+       dev_info(&(cpcap_di->spi->dev), "Saving power down reason.\n");
+
+       if (code == SYS_RESTART) {
+               if (mode != NULL && !strncmp("outofcharge", mode, 12)) {
+                       /* Set the outofcharge bit in the cpcap */
+                       ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                                                CPCAP_BIT_OUT_CHARGE_ONLY,
+                                                CPCAP_BIT_OUT_CHARGE_ONLY);
+                       if (ret) {
+                               dev_err(&(cpcap_di->spi->dev),
+                                       "outofcharge cpcap set failure.\n");
+                               result = NOTIFY_BAD;
+                       }
+                       /* Set the soft reset bit in the cpcap */
+                       cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                                          CPCAP_BIT_SOFT_RESET,
+                                          CPCAP_BIT_SOFT_RESET);
+                       if (ret) {
+                               dev_err(&(cpcap_di->spi->dev),
+                                       "reset cpcap set failure.\n");
+                               result = NOTIFY_BAD;
+                       }
+               }
+
+               /* Check if we are starting recovery mode */
+               if (mode != NULL && !strncmp("recovery", mode, 9)) {
+                       /* Set the fota (recovery mode) bit in the cpcap */
+                       ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                               CPCAP_BIT_FOTA_MODE, CPCAP_BIT_FOTA_MODE);
+                       if (ret) {
+                               dev_err(&(cpcap_di->spi->dev),
+                                       "Recovery cpcap set failure.\n");
+                               result = NOTIFY_BAD;
+                       }
+               } else {
+                       /* Set the fota (recovery mode) bit in the cpcap */
+                       ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1, 0,
+                                                CPCAP_BIT_FOTA_MODE);
+                       if (ret) {
+                               dev_err(&(cpcap_di->spi->dev),
+                                       "Recovery cpcap clear failure.\n");
+                               result = NOTIFY_BAD;
+                       }
+               }
+               /* Check if we are going into fast boot mode */
+               if (mode != NULL && !strncmp("bootloader", mode, 11)) {
+                       /* Set the bootmode bit in the cpcap */
+                       ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                               CPCAP_BIT_BOOT_MODE, CPCAP_BIT_BOOT_MODE);
+                       if (ret) {
+                               dev_err(&(cpcap_di->spi->dev),
+                                       "Boot mode cpcap set failure.\n");
+                               result = NOTIFY_BAD;
+                       }
+               }
+       } else {
+               ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                                        0,
+                                        CPCAP_BIT_OUT_CHARGE_ONLY);
+               if (ret) {
+                       dev_err(&(cpcap_di->spi->dev),
+                               "outofcharge cpcap set failure.\n");
+                       result = NOTIFY_BAD;
+               }
+
+               /* Clear the soft reset bit in the cpcap */
+               ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1, 0,
+                                        CPCAP_BIT_SOFT_RESET);
+               if (ret) {
+                       dev_err(&(cpcap_di->spi->dev),
+                               "SW Reset cpcap set failure.\n");
+                       result = NOTIFY_BAD;
+               }
+               /* Clear the fota (recovery mode) bit in the cpcap */
+               ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1, 0,
+                                        CPCAP_BIT_FOTA_MODE);
+               if (ret) {
+                       dev_err(&(cpcap_di->spi->dev),
+                               "Recovery cpcap clear failure.\n");
+                       result = NOTIFY_BAD;
+               }
+       }
+
+       /* Always clear the kpanic bit */
+       ret = cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                                0, CPCAP_BIT_AP_KERNEL_PANIC);
+       if (ret) {
+               dev_err(&(cpcap_di->spi->dev),
+                       "Clear kernel panic bit failure.\n");
+               result = NOTIFY_BAD;
+       }
+
+       return result;
+}
+static struct notifier_block validity_reboot_notifier = {
+       .notifier_call = cpcap_validity_reboot,
+};
+
+static int cpcap_validity_probe(struct platform_device *pdev)
+{
+       if (pdev->dev.platform_data == NULL) {
+               dev_err(&pdev->dev, "no platform_data\n");
+               return -EINVAL;
+       }
+
+       cpcap_di = pdev->dev.platform_data;
+
+       cpcap_regacc_write(cpcap_di, CPCAP_REG_VAL1,
+                          (CPCAP_BIT_AP_KERNEL_PANIC | CPCAP_BIT_SOFT_RESET),
+                          (CPCAP_BIT_AP_KERNEL_PANIC | CPCAP_BIT_SOFT_RESET));
+
+       register_reboot_notifier(&validity_reboot_notifier);
+
+       return 0;
+}
+
+static int cpcap_validity_remove(struct platform_device *pdev)
+{
+       unregister_reboot_notifier(&validity_reboot_notifier);
+       cpcap_di = NULL;
+
+       return 0;
+}
+
+static struct platform_driver cpcap_validity_driver = {
+       .probe = cpcap_validity_probe,
+       .remove = cpcap_validity_remove,
+       .driver = {
+               .name = "cpcap_validity",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static struct platform_device cpcap_validity_device = {
+       .name   = "cpcap_validity",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = NULL,
+       },
+};
+
+static struct platform_device cpcap_3mm5_device = {
+       .name   = "cpcap_3mm5",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = NULL,
+       },
+};
+
+static struct cpcap_whisper_pdata whisper_pdata = {
+       .gpio    = TEGRA_GPIO_PV4,
+       .uartmux = 1,
+};
+
+static struct platform_device cpcap_whisper_device = {
+       .name   = "cpcap_whisper",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &whisper_pdata,
+       },
+};
+
+static struct platform_device *cpcap_devices[] = {
+       &cpcap_validity_device,
+       &cpcap_whisper_device,
+       &cpcap_3mm5_device,
+};
+
+struct cpcap_spi_init_data stingray_cpcap_spi_init[] = {
+       {CPCAP_REG_ADCC1,     0x9000},
+       {CPCAP_REG_ADCC2,     0x4136},
+       {CPCAP_REG_USBC1,     0x1201},
+       {CPCAP_REG_USBC3,     0x7DFB},
+       {CPCAP_REG_OWDC,      0x0003},
+};
+
+unsigned short cpcap_regulator_mode_values[CPCAP_NUM_REGULATORS] = {
+       [CPCAP_SW5]      = 0x0022,
+       [CPCAP_VCAM]     = 0x0003,
+       [CPCAP_VCSI]     = 0x0003,
+       [CPCAP_VDAC]     = 0x0003,
+       [CPCAP_VDIG]     = 0x0003,
+       [CPCAP_VFUSE]    = 0x0080,
+       [CPCAP_VHVIO]    = 0x0003,
+       [CPCAP_VSDIO]    = 0x0003,
+       [CPCAP_VPLL]     = 0x0042,
+       [CPCAP_VRF1]     = 0x000C,
+       [CPCAP_VRF2]     = 0x0003,
+       [CPCAP_VRFREF]   = 0x0003,
+       [CPCAP_VWLAN1]   = 0x0003,
+       [CPCAP_VWLAN2]   = 0x000C,
+       [CPCAP_VSIM]     = 0x0003,
+       [CPCAP_VSIMCARD] = 0x1E00,
+       [CPCAP_VVIB]     = 0x0001,
+       [CPCAP_VUSB]     = 0x000C,
+       [CPCAP_VAUDIO]   = 0x0006,
+};
+
+unsigned short cpcap_regulator_off_mode_values[CPCAP_NUM_REGULATORS] = {
+       [CPCAP_SW5]      = 0x0000,
+       [CPCAP_VCAM]     = 0x0000,
+       [CPCAP_VCSI]     = 0x0000,
+       [CPCAP_VDAC]     = 0x0000,
+       [CPCAP_VDIG]     = 0x0000,
+       [CPCAP_VFUSE]    = 0x0000,
+       [CPCAP_VHVIO]    = 0x0000,
+       [CPCAP_VSDIO]    = 0x0000,
+       [CPCAP_VPLL]     = 0x0000,
+       [CPCAP_VRF1]     = 0x0000,
+       [CPCAP_VRF2]     = 0x0000,
+       [CPCAP_VRFREF]   = 0x0000,
+       [CPCAP_VWLAN1]   = 0x0000,
+       [CPCAP_VWLAN2]   = 0x0000,
+       [CPCAP_VSIM]     = 0x0000,
+       [CPCAP_VSIMCARD] = 0x0000,
+       [CPCAP_VVIB]     = 0x0000,
+       [CPCAP_VUSB]     = 0x0000,
+       [CPCAP_VAUDIO]   = 0x0000,
+};
+
+#define REGULATOR_CONSUMER(name, device) { .supply = name, .dev = device, }
+
+struct regulator_consumer_supply cpcap_sw5_consumers[] = {
+       REGULATOR_CONSUMER("sw5", NULL),
+};
+
+struct regulator_consumer_supply cpcap_vcam_consumers[] = {
+       REGULATOR_CONSUMER("vcam", NULL /* cpcap_cam_device */),
+};
+
+struct regulator_consumer_supply cpcap_vhvio_consumers[] = {
+       REGULATOR_CONSUMER("vhvio", NULL /* lighting_driver */),
+#if 0
+       REGULATOR_CONSUMER("vhvio", NULL /* lighting_driver */),
+       REGULATOR_CONSUMER("vhvio", NULL /* magnetometer */),
+       REGULATOR_CONSUMER("vhvio", NULL /* light sensor */),
+       REGULATOR_CONSUMER("vhvio", NULL /* accelerometer */),
+       REGULATOR_CONSUMER("vhvio", NULL /* display */),
+#endif
+};
+
+struct regulator_consumer_supply cpcap_vsdio_consumers[] = {
+       REGULATOR_CONSUMER("vsdio", NULL),
+};
+
+struct regulator_consumer_supply cpcap_vcsi_consumers[] = {
+       REGULATOR_CONSUMER("vcsi", NULL),
+};
+
+struct regulator_consumer_supply cpcap_vwlan2_consumers[] = {
+       REGULATOR_CONSUMER("vwlan2", NULL /* sd slot */),
+};
+
+struct regulator_consumer_supply cpcap_vvib_consumers[] = {
+       REGULATOR_CONSUMER("vvib", NULL /* vibrator */),
+};
+
+struct regulator_consumer_supply cpcap_vusb_consumers[] = {
+       REGULATOR_CONSUMER("vusb", &cpcap_whisper_device.dev),
+};
+
+struct regulator_consumer_supply cpcap_vaudio_consumers[] = {
+       REGULATOR_CONSUMER("vaudio", NULL /* mic opamp */),
+};
+
+static struct regulator_init_data cpcap_regulator[CPCAP_NUM_REGULATORS] = {
+       [CPCAP_SW5] = {
+               .constraints = {
+                       .min_uV                 = 5050000,
+                       .max_uV                 = 5050000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_sw5_consumers),
+               .consumer_supplies      = cpcap_sw5_consumers,
+       },
+       [CPCAP_VCAM] = {
+               .constraints = {
+                       .min_uV                 = 2900000,
+                       .max_uV                 = 2900000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .apply_uV               = 1,
+
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vcam_consumers),
+               .consumer_supplies      = cpcap_vcam_consumers,
+       },
+       [CPCAP_VCSI] = {
+               .constraints = {
+                       .min_uV                 = 1200000,
+                       .max_uV                 = 1200000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .boot_on                = 1,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vcsi_consumers),
+               .consumer_supplies      = cpcap_vcsi_consumers,
+       },
+       [CPCAP_VDAC] = {
+               .constraints = {
+                       .min_uV                 = 1800000,
+                       .max_uV                 = 1800000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .apply_uV               = 1,
+               },
+       },
+       [CPCAP_VDIG] = {
+               .constraints = {
+                       .min_uV                 = 1200000,
+                       .max_uV                 = 1875000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VFUSE] = {
+               .constraints = {
+                       .min_uV                 = 1500000,
+                       .max_uV                 = 3150000,
+                       .valid_ops_mask         = (REGULATOR_CHANGE_VOLTAGE |
+                                                  REGULATOR_CHANGE_STATUS),
+               },
+       },
+       [CPCAP_VHVIO] = {
+               .constraints = {
+                       .min_uV                 = 2775000,
+                       .max_uV                 = 2775000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .always_on              = 1,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vhvio_consumers),
+               .consumer_supplies      = cpcap_vhvio_consumers,
+       },
+       [CPCAP_VSDIO] = {
+               .constraints = {
+                       .min_uV                 = 3000000,
+                       .max_uV                 = 3000000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vsdio_consumers),
+               .consumer_supplies      = cpcap_vsdio_consumers,
+       },
+       [CPCAP_VPLL] = {
+               .constraints = {
+                       .min_uV                 = 1800000,
+                       .max_uV                 = 1800000,
+                       .valid_ops_mask         = 0,
+                       .always_on              = 1,
+                       .apply_uV               = 1,
+               },
+       },
+       [CPCAP_VRF1] = {
+               .constraints = {
+                       .min_uV                 = 2500000,
+                       .max_uV                 = 2775000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VRF2] = {
+               .constraints = {
+                       .min_uV                 = 2775000,
+                       .max_uV                 = 2775000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VRFREF] = {
+               .constraints = {
+                       .min_uV                 = 2500000,
+                       .max_uV                 = 2775000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VWLAN1] = {
+               .constraints = {
+                       .min_uV                 = 1800000,
+                       .max_uV                 = 1900000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VWLAN2] = {
+               .constraints = {
+                       .min_uV                 = 3300000,
+                       .max_uV                 = 3300000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vwlan2_consumers),
+               .consumer_supplies      = cpcap_vwlan2_consumers,
+       },
+       [CPCAP_VSIM] = {
+               .constraints = {
+                       .min_uV                 = 1800000,
+                       .max_uV                 = 2900000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VSIMCARD] = {
+               .constraints = {
+                       .min_uV                 = 1800000,
+                       .max_uV                 = 2900000,
+                       .valid_ops_mask         = 0,
+               },
+       },
+       [CPCAP_VVIB] = {
+               .constraints = {
+                       .min_uV                 = 1300000,
+                       .max_uV                 = 3000000,
+                       .valid_ops_mask         = (REGULATOR_CHANGE_VOLTAGE |
+                                                  REGULATOR_CHANGE_STATUS),
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vvib_consumers),
+               .consumer_supplies      = cpcap_vvib_consumers,
+       },
+       [CPCAP_VUSB] = {
+               .constraints = {
+                       .min_uV                 = 3300000,
+                       .max_uV                 = 3300000,
+                       .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vusb_consumers),
+               .consumer_supplies      = cpcap_vusb_consumers,
+       },
+       [CPCAP_VAUDIO] = {
+               .constraints = {
+                       .min_uV                 = 2775000,
+                       .max_uV                 = 2775000,
+                       .valid_modes_mask       = (REGULATOR_MODE_NORMAL |
+                                                  REGULATOR_MODE_STANDBY),
+                       .valid_ops_mask         = REGULATOR_CHANGE_MODE,
+                       .always_on              = 1,
+                       .apply_uV               = 1,
+               },
+               .num_consumer_supplies  = ARRAY_SIZE(cpcap_vaudio_consumers),
+               .consumer_supplies      = cpcap_vaudio_consumers,
+       },
+};
+
+static struct cpcap_adc_ato stingray_cpcap_adc_ato = {
+       .ato_in = 0x0480,
+       .atox_in = 0,
+       .adc_ps_factor_in = 0x0200,
+       .atox_ps_factor_in = 0,
+       .ato_out = 0,
+       .atox_out = 0,
+       .adc_ps_factor_out = 0,
+       .atox_ps_factor_out = 0,
+};
+
+static struct cpcap_leds stingray_cpcap_leds = {
+       .button_led = {
+               .button_reg = CPCAP_REG_KLC,
+               .button_mask = 0x03FF,
+               .button_on = 0x00F5,
+               .button_off = 0x00F4,
+       },
+       .rgb_led = {
+               .rgb_on = 0x0053,
+       },
+};
+
+static struct cpcap_platform_data stingray_cpcap_data = {
+       .init = stingray_cpcap_spi_init,
+       .init_len = ARRAY_SIZE(stingray_cpcap_spi_init),
+       .regulator_mode_values = cpcap_regulator_mode_values,
+       .regulator_off_mode_values = cpcap_regulator_off_mode_values,
+       .regulator_init = cpcap_regulator,
+       .adc_ato = &stingray_cpcap_adc_ato,
+       .leds = &stingray_cpcap_leds,
+       .ac_changed = NULL,
+       .batt_changed = NULL,
+       .usb_changed = NULL,
+};
+
+static struct spi_board_info stingray_spi_board_info[] __initdata = {
+       {
+               .modalias = "cpcap",
+               .bus_num = 1,
+               .chip_select = 0,
+               .mode = SPI_MODE_0,
+               .max_speed_hz = 10000000,
+               .controller_data = &stingray_cpcap_data,
+               .irq = INT_EXTERNAL_PMU,
+       },
+};
+
+int __init stingray_spi_init(void)
+{
+       int i;
+
+       spi_register_board_info(stingray_spi_board_info,
+                               ARRAY_SIZE(stingray_spi_board_info));
+
+       for (i = 0; i < ARRAY_SIZE(cpcap_devices); i++)
+               cpcap_device_register(cpcap_devices[i]);
+
+       (void) cpcap_driver_register(&cpcap_validity_driver);
+
+       return 0;
+}
index 61a8757aaae993f3cf59fee55dbdf4e227deaca2..40ceb036b5d9f44510dc310755a90723f580f716 100644 (file)
@@ -302,6 +302,7 @@ static void __init tegra_stingray_init(void)
 
        stingray_keypad_init();
        stingray_touch_init();
+       stingray_spi_init();
        stingray_panel_init();
        stingray_sdhci_init();
        stingray_sensors_init();
index 50979eb701955449a2bf442b22cd5b7bd6654133..336f7ba40b971ad6a54f88f469fc7eeba4a3a746 100644 (file)
@@ -24,5 +24,6 @@ int stingray_i2c_init(void);
 int stingray_wlan_init(void);
 int stingray_sensors_init(void);
 int stingray_touch_init(void);
+int stingray_spi_init(void);
 
 #endif