blob: e5f65e720656db1e0349e2d981e50f514eac8f2f [file] [log] [blame]
/* linux/arch/arm/mach-msm/devices.c
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2007-2009 HTC Corporation.
* Author: Thomas Tsai <thomas_tsai@htc.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <mach/msm_iomap.h>
#include <mach/dma.h>
#include "gpio_chip.h"
#include "devices.h"
#include <mach/board.h>
#include <mach/board_htc.h>
#include <mach/msm_hsusb.h>
#include <linux/usb/android_composite.h>
#include <asm/mach/flash.h>
#include <asm/setup.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/android_pmem.h>
#include <mach/msm_rpcrouter.h>
#include <mach/msm_iomap.h>
#include <asm/mach/mmc.h>
static char *df_serialno = "000000000000";
#if 0
struct platform_device *devices[] __initdata = {
&msm_device_nand,
&msm_device_smd,
&msm_device_i2c,
};
void __init msm_add_devices(void)
{
platform_add_devices(devices, ARRAY_SIZE(devices));
}
#endif
#define HSUSB_API_INIT_PHY_PROC 2
#define HSUSB_API_PROG 0x30000064
#define HSUSB_API_VERS MSM_RPC_VERS(1,1)
static void internal_phy_reset(void)
{
struct msm_rpc_endpoint *usb_ep;
int rc;
struct hsusb_phy_start_req {
struct rpc_request_hdr hdr;
} req;
printk(KERN_INFO "msm_hsusb_phy_reset\n");
usb_ep = msm_rpc_connect(HSUSB_API_PROG, HSUSB_API_VERS, 0);
if (IS_ERR(usb_ep)) {
printk(KERN_ERR "%s: init rpc failed! error: %ld\n",
__func__, PTR_ERR(usb_ep));
goto close;
}
rc = msm_rpc_call(usb_ep, HSUSB_API_INIT_PHY_PROC,
&req, sizeof(req), 5 * HZ);
if (rc < 0)
printk(KERN_ERR "%s: rpc call failed! (%d)\n", __func__, rc);
close:
msm_rpc_close(usb_ep);
}
/* adjust eye diagram, disable vbusvalid interrupts */
static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 };
struct msm_hsusb_platform_data msm_hsusb_pdata = {
.phy_reset = internal_phy_reset,
.phy_init_seq = hsusb_phy_init_seq,
.usb_connected = notify_usb_connected,
};
static struct usb_mass_storage_platform_data mass_storage_pdata = {
.nluns = 1,
.vendor = "HTC ",
.product = "Android Phone ",
.release = 0x0100,
};
static struct platform_device usb_mass_storage_device = {
.name = "usb_mass_storage",
.id = -1,
.dev = {
.platform_data = &mass_storage_pdata,
},
};
#ifdef CONFIG_USB_ANDROID_RNDIS
static struct usb_ether_platform_data rndis_pdata = {
/* ethaddr is filled by board_serialno_setup */
.vendorID = 0x0bb4,
.vendorDescr = "HTC",
};
static struct platform_device rndis_device = {
.name = "rndis",
.id = -1,
.dev = {
.platform_data = &rndis_pdata,
},
};
#endif
static char *usb_functions_ums[] = {
"usb_mass_storage",
};
static char *usb_functions_ums_adb[] = {
"usb_mass_storage",
"adb",
};
static char *usb_functions_rndis[] = {
"rndis",
};
static char *usb_functions_rndis_adb[] = {
"rndis",
"adb",
};
static char *usb_functions_all[] = {
#ifdef CONFIG_USB_ANDROID_RNDIS
"rndis",
#endif
"usb_mass_storage",
"adb",
#ifdef CONFIG_USB_ANDROID_ACM
"acm",
#endif
};
static struct android_usb_product usb_products[] = {
{
.product_id = 0x0c01,
.num_functions = ARRAY_SIZE(usb_functions_ums),
.functions = usb_functions_ums,
},
{
.product_id = 0x0c02,
.num_functions = ARRAY_SIZE(usb_functions_ums_adb),
.functions = usb_functions_ums_adb,
},
{
.product_id = 0x0ffe,
.num_functions = ARRAY_SIZE(usb_functions_rndis),
.functions = usb_functions_rndis,
},
{
.product_id = 0x0ffc,
.num_functions = ARRAY_SIZE(usb_functions_rndis_adb),
.functions = usb_functions_rndis_adb,
},
};
static struct android_usb_platform_data android_usb_pdata = {
.vendor_id = 0x0bb4,
.product_id = 0x0c01,
.version = 0x0100,
.product_name = "Android Phone",
.manufacturer_name = "HTC",
.num_products = ARRAY_SIZE(usb_products),
.products = usb_products,
.num_functions = ARRAY_SIZE(usb_functions_all),
.functions = usb_functions_all,
};
static struct platform_device android_usb_device = {
.name = "android_usb",
.id = -1,
.dev = {
.platform_data = &android_usb_pdata,
},
};
void __init msm_add_usb_devices(void (*phy_reset) (void))
{
/* setup */
if (phy_reset)
msm_hsusb_pdata.phy_reset = phy_reset;
msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
platform_device_register(&msm_device_hsusb);
#ifdef CONFIG_USB_ANDROID_RNDIS
platform_device_register(&rndis_device);
#endif
platform_device_register(&usb_mass_storage_device);
platform_device_register(&android_usb_device);
}
static struct android_pmem_platform_data pmem_pdata = {
.name = "pmem",
.no_allocator = 1,
.cached = 1,
};
static struct android_pmem_platform_data pmem_adsp_pdata = {
.name = "pmem_adsp",
.no_allocator = 0,
.cached = 0,
};
static struct android_pmem_platform_data pmem_camera_pdata = {
.name = "pmem_camera",
.no_allocator = 1,
.cached = 0,
};
static struct platform_device pmem_device = {
.name = "android_pmem",
.id = 0,
.dev = { .platform_data = &pmem_pdata },
};
static struct platform_device pmem_adsp_device = {
.name = "android_pmem",
.id = 1,
.dev = { .platform_data = &pmem_adsp_pdata },
};
static struct platform_device pmem_camera_device = {
.name = "android_pmem",
.id = 2,
.dev = { .platform_data = &pmem_camera_pdata },
};
static struct resource ram_console_resource[] = {
{
.flags = IORESOURCE_MEM,
}
};
static struct platform_device ram_console_device = {
.name = "ram_console",
.id = -1,
.num_resources = ARRAY_SIZE(ram_console_resource),
.resource = ram_console_resource,
};
static struct resource resources_hw3d[] = {
{
.start = 0xA0000000,
.end = 0xA00fffff,
.flags = IORESOURCE_MEM,
.name = "regs",
},
{
.flags = IORESOURCE_MEM,
.name = "smi",
},
{
.flags = IORESOURCE_MEM,
.name = "ebi",
},
{
.start = INT_GRAPHICS,
.end = INT_GRAPHICS,
.flags = IORESOURCE_IRQ,
.name = "gfx",
},
};
static struct platform_device hw3d_device = {
.name = "msm_hw3d",
.id = 0,
.num_resources = ARRAY_SIZE(resources_hw3d),
.resource = resources_hw3d,
};
void __init msm_add_mem_devices(struct msm_pmem_setting *setting)
{
if (setting->pmem_size) {
pmem_pdata.start = setting->pmem_start;
pmem_pdata.size = setting->pmem_size;
platform_device_register(&pmem_device);
}
if (setting->pmem_adsp_size) {
pmem_adsp_pdata.start = setting->pmem_adsp_start;
pmem_adsp_pdata.size = setting->pmem_adsp_size;
platform_device_register(&pmem_adsp_device);
}
if (setting->pmem_gpu0_size && setting->pmem_gpu1_size) {
struct resource *res;
res = platform_get_resource_byname(&hw3d_device, IORESOURCE_MEM,
"smi");
res->start = setting->pmem_gpu0_start;
res->end = res->start + setting->pmem_gpu0_size - 1;
res = platform_get_resource_byname(&hw3d_device, IORESOURCE_MEM,
"ebi");
res->start = setting->pmem_gpu1_start;
res->end = res->start + setting->pmem_gpu1_size - 1;
platform_device_register(&hw3d_device);
}
if (setting->pmem_camera_size) {
pmem_camera_pdata.start = setting->pmem_camera_start;
pmem_camera_pdata.size = setting->pmem_camera_size;
platform_device_register(&pmem_camera_device);
}
if (setting->ram_console_size) {
ram_console_resource[0].start = setting->ram_console_start;
ram_console_resource[0].end = setting->ram_console_start
+ setting->ram_console_size - 1;
platform_device_register(&ram_console_device);
}
}
#define PM_LIBPROG 0x30000061
#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
#define PM_LIBVERS 0xfb837d0b
#else
#define PM_LIBVERS 0x10001
#endif
#if 0
static struct platform_device *msm_serial_devices[] __initdata = {
&msm_device_uart1,
&msm_device_uart2,
&msm_device_uart3,
#ifdef CONFIG_SERIAL_MSM_HS
&msm_device_uart_dm1,
&msm_device_uart_dm2,
#endif
};
int __init msm_add_serial_devices(unsigned num)
{
if (num > MSM_SERIAL_NUM)
return -EINVAL;
return platform_device_register(msm_serial_devices[num]);
}
#endif
#define ATAG_SMI 0x4d534D71
/* setup calls mach->fixup, then parse_tags, parse_cmdline
* We need to setup meminfo in mach->fixup, so this function
* will need to traverse each tag to find smi tag.
*/
int __init parse_tag_smi(const struct tag *tags)
{
int smi_sz = 0, find = 0;
struct tag *t = (struct tag *)tags;
for (; t->hdr.size; t = tag_next(t)) {
if (t->hdr.tag == ATAG_SMI) {
printk(KERN_DEBUG "find the smi tag\n");
find = 1;
break;
}
}
if (!find)
return -1;
printk(KERN_DEBUG "parse_tag_smi: smi size = %d\n", t->u.mem.size);
smi_sz = t->u.mem.size;
return smi_sz;
}
__tagtable(ATAG_SMI, parse_tag_smi);
#define ATAG_HWID 0x4d534D72
int __init parse_tag_hwid(const struct tag *tags)
{
int hwid = 0, find = 0;
struct tag *t = (struct tag *)tags;
for (; t->hdr.size; t = tag_next(t)) {
if (t->hdr.tag == ATAG_HWID) {
printk(KERN_DEBUG "find the hwid tag\n");
find = 1;
break;
}
}
if (find)
hwid = t->u.revision.rev;
printk(KERN_DEBUG "parse_tag_hwid: hwid = 0x%x\n", hwid);
return hwid;
}
__tagtable(ATAG_HWID, parse_tag_hwid);
#define ATAG_SKUID 0x4d534D73
int __init parse_tag_skuid(const struct tag *tags)
{
int skuid = 0, find = 0;
struct tag *t = (struct tag *)tags;
for (; t->hdr.size; t = tag_next(t)) {
if (t->hdr.tag == ATAG_SKUID) {
printk(KERN_DEBUG "find the skuid tag\n");
find = 1;
break;
}
}
if (find)
skuid = t->u.revision.rev;
printk(KERN_DEBUG "parse_tag_skuid: hwid = 0x%x\n", skuid);
return skuid;
}
__tagtable(ATAG_SKUID, parse_tag_skuid);
#define ATAG_ENGINEERID 0x4d534D75
int __init parse_tag_engineerid(const struct tag *tags)
{
int engineerid = 0, find = 0;
struct tag *t = (struct tag *)tags;
for (; t->hdr.size; t = tag_next(t)) {
if (t->hdr.tag == ATAG_ENGINEERID) {
printk(KERN_DEBUG "find the engineer tag\n");
find = 1;
break;
}
}
if (find)
engineerid = t->u.revision.rev;
printk(KERN_DEBUG "parse_tag_engineerid: hwid = 0x%x\n", engineerid);
return engineerid;
}
__tagtable(ATAG_ENGINEERID, parse_tag_engineerid);
static int mfg_mode;
int __init board_mfg_mode_init(char *s)
{
if (!strcmp(s, "normal"))
mfg_mode = 0;
else if (!strcmp(s, "factory2"))
mfg_mode = 1;
else if (!strcmp(s, "recovery"))
mfg_mode = 2;
else if (!strcmp(s, "charge"))
mfg_mode = 3;
return 1;
}
__setup("androidboot.mode=", board_mfg_mode_init);
int board_mfg_mode(void)
{
return mfg_mode;
}
static int __init board_serialno_setup(char *serialno)
{
#ifdef CONFIG_USB_ANDROID_RNDIS
int i;
char *src;
#endif
char *str;
/* use default serial number when mode is factory2 */
if (mfg_mode == 1 || !strlen(serialno))
str = df_serialno;
else
str = serialno;
#ifdef CONFIG_USB_ANDROID_RNDIS
/* create a fake MAC address from our serial number.
* first byte is 0x02 to signify locally administered.
*/
rndis_pdata.ethaddr[0] = 0x02;
src = str;
for (i = 0; *src; i++) {
/* XOR the USB serial across the remaining bytes */
rndis_pdata.ethaddr[i % (ETH_ALEN - 1) + 1] ^= *src++;
}
#endif
android_usb_pdata.serial_number = str;
return 1;
}
__setup("androidboot.serialno=", board_serialno_setup);