Index: linux-2.6.21/arch/arm/mach-pxa/ezx-eoc.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.21/arch/arm/mach-pxa/ezx-eoc.c 2007-09-11 20:14:33.000000000 -0300 @@ -0,0 +1,267 @@ +/* + * EZX EOC Driver for Motorola EZX phones + * + * Copyright (C) 2007 Alex Zhang + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "ezx-eoc.h" + +#if 1 +#define EOC_DBG printk +#else +#define EOC_DBG(x, args...) +#endif + +#define EOC_REG_ADDR_SIZE 1 +#define EOC_REG_DATA_SIZE 3 + +struct ezx_eoc_platform_data *pdata; +static int eoc_func = EOC_FUNC_USB_NET; +static const char eoc_i2c_driver_name[] = "ezx-eoc"; + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + 0x17, /* Address for version 2.0 and above */ + // 0x7C, /* Address for versions prior too 2.0 */ + I2C_CLIENT_END +}; + +/* I2C Magic */ +I2C_CLIENT_INSMOD; + +static int ezx_eoc_attach_adapter(struct i2c_adapter *adapter); +static int ezx_eoc_detect(struct i2c_adapter *adapter, int address, int kind); +static int ezx_eoc_detach_client(struct i2c_client *client); + +static struct i2c_client *eoc_i2c_client = NULL; + +static struct i2c_driver eoc_i2c_driver = { + .driver = { + .name = (char *)eoc_i2c_driver_name, + }, + .id = I2C_DRIVERID_EEPROM, + .attach_adapter = ezx_eoc_attach_adapter, + .detach_client = ezx_eoc_detach_client, +}; + +int eoc_reg_read(int reg, unsigned int *reg_value) +{ + unsigned char reg_num = reg; + unsigned char value[EOC_REG_DATA_SIZE]; + int retval; + + struct i2c_msg msgs[2] = + { + { 0, 0, EOC_REG_ADDR_SIZE, ®_num }, + { 0, I2C_M_RD, EOC_REG_DATA_SIZE, value } + }; + + /* check if we have initialized */ /*not necessary --WM + if (eoc_i2c_client == NULL) + { + EOC_DBG("eoc_reg_read: not initialized\n"); + return -EINVAL; + } +*/ + msgs[0].addr = msgs[1].addr = eoc_i2c_client->addr; + + /* transfer message to client */ + retval = i2c_transfer(eoc_i2c_client->adapter, msgs, 2); + if (retval >= 0) + { + *reg_value = (value[2] << 0); + *reg_value |= (value[1] << 8); + *reg_value |= (value[0] << 16); + } + return retval; +} +EXPORT_SYMBOL_GPL(eoc_reg_read); + +int eoc_reg_write(int reg, unsigned int reg_value) +{ + unsigned char value[EOC_REG_ADDR_SIZE + EOC_REG_DATA_SIZE]; + int retval; + + /* check if we have initialized */ /*not necessary --WM + if (eoc_i2c_client == NULL) + { + EOC_DBG("eoc_reg_write: not initialized\n"); + return -EINVAL; + } +*/ + /* Copy the data into a buffer into the correct format */ + value[0] = reg; + value[1] = (reg_value >> 16) & 0xFF; + value[2] = (reg_value >> 8) & 0xFF; + value[3] = (reg_value >> 0) & 0xFF; + + /* Write the data to the EOC */ + retval = i2c_master_send (eoc_i2c_client, value, EOC_REG_ADDR_SIZE + EOC_REG_DATA_SIZE); + + return retval; +} +EXPORT_SYMBOL_GPL(eoc_reg_write); + +static void eoc_switch_to_usb(void) +{ + pxa_gpio_mode(GPIO34_USB_P2_2_MD); + pxa_gpio_mode(GPIO35_USB_P2_1_MD); + pxa_gpio_mode(GPIO36_USB_P2_4_MD); + pxa_gpio_mode(GPIO39_USB_P2_6_MD); + pxa_gpio_mode(GPIO40_USB_P2_5_MD); + pxa_gpio_mode(GPIO53_USB_P2_3_MD); + EOC_DBG("ALEX;*********************************************emu_switch_to_usb;\n"); +} + +static void eoc_switch_to_nothing(void) +{ + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); +} + +static void eoc_switch_to_default(void) +{ + switch (eoc_func) { + case EOC_FUNC_USB_NET: + eoc_switch_to_usb(); + break; + case EOC_FUNC_NOTHING: + eoc_switch_to_nothing(); + break; + } +} + + +static int ezx_eoc_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, ezx_eoc_detect); +} + +/* This function is called by i2c_probe */ +static int ezx_eoc_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + int err = 0; + + if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) + return -ENOMEM; + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &eoc_i2c_driver; + new_client->flags = 0; + strlcpy(new_client->name, eoc_i2c_driver_name, I2C_NAME_SIZE); + + if ((err = i2c_attach_client(new_client))) { + kfree(new_client); + return err; + } + + eoc_i2c_client = new_client; + + if (pdata && pdata->init) + pdata->init(); + + eoc_switch_to_default(); + + return 0; +} + +static int ezx_eoc_detach_client(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) + return err; + + return 0; +} + +static int __init ezx_eoc_probe(struct platform_device *dev) +{ + int ret; + + pdata = dev->dev.platform_data; + + ret = i2c_add_driver(&eoc_i2c_driver); + if (ret != 0) + return -EINVAL; + + /* + * I think we should save platform_data and call init and eoc_switch + * from ezx_eoc_detect, after client is setup. + * And there is no need for all the "check if initialised" checks if + * you assure that you only call read/write after the client is set. + * Probably, this was causing the crash on i2c-core too. + * --WM + */ + + /* FIXME: should set udc_info here -WM */ + return 0; +} + +static int ezx_eoc_remove(struct platform_device *dev) +{ + return i2c_del_driver(&eoc_i2c_driver); +} + +static int ezx_eoc_suspend(struct platform_device *dev, pm_message_t state) +{ + eoc_switch_to_nothing(); + return 0; +} + +static int ezx_eoc_resume(struct platform_device *dev) +{ + eoc_switch_to_default(); + return 0; +} + +static struct platform_driver ezx_eoc_driver = { + .probe = ezx_eoc_probe, + .remove = ezx_eoc_remove, + .suspend = ezx_eoc_suspend, + .resume = ezx_eoc_resume, + .driver = { + .name = "ezx-eoc", + .owner = THIS_MODULE, + }, +}; + +int __init ezx_eoc_init(void) +{ + return platform_driver_register(&ezx_eoc_driver); +} + +void ezx_eoc_exit(void) +{ + return platform_driver_unregister(&ezx_eoc_driver); +} + +MODULE_AUTHOR("Alex Zhang "); +MODULE_DESCRIPTION("EZX EOC I2C driver"); +MODULE_LICENSE("GPL"); + +/* doesnt module_init work?? -WM */ +/*late_initcall(ezx_eoc_init);*/ +module_init(ezx_eoc_init); +module_exit(ezx_eoc_exit); Index: linux-2.6.21/arch/arm/mach-pxa/ezx-eoc.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.21/arch/arm/mach-pxa/ezx-eoc.h 2007-09-09 21:46:27.000000000 -0300 @@ -0,0 +1,33 @@ +/* + * linux/arch/arm/mach-pxa/ezx-eoc.h + * + * Copyright (C) Alex Zhang + * + * 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. + */ + +#ifndef __EZX_EOC_H__ +#define __EZX_EOC_H__ + +enum { + POWER_IC_REG_EOC_INT_STATUS, + POWER_IC_REG_EOC_INT_MASK, + POWER_IC_REG_EOC_INT_SENSE, + POWER_IC_REG_EOC_POWER_CONTROL_0, + POWER_IC_REG_EOC_POWER_CONTROL_1, + POWER_IC_REG_EOC_CONN_CONTROL, + POWER_IC_REG_EOC_NUM +}; + +enum { + EOC_FUNC_NOTHING, + EOC_FUNC_USB_NET, +}; + +struct ezx_eoc_platform_data { + int (*init)(void); +}; + +#endif /* __EZX_EOC_H__ */ Index: linux-2.6.21/arch/arm/mach-pxa/Kconfig =================================================================== --- linux-2.6.21.orig/arch/arm/mach-pxa/Kconfig 2007-09-09 21:46:27.000000000 -0300 +++ linux-2.6.21/arch/arm/mach-pxa/Kconfig 2007-09-09 21:46:27.000000000 -0300 @@ -108,6 +108,12 @@ config EZX_PCAP bool "PCAP Support" +config EZX_EOC + tristate "EOC i2c driver of Motorola EZX phones" + depends on I2C && EXPERIMENTAL + help + EOC i2c driver of Motorola EZX phones + config EZX_EMU bool "Motorola Enchanced Mini Usb" depends on EZX_PCAP Index: linux-2.6.21/arch/arm/mach-pxa/Makefile =================================================================== --- linux-2.6.21.orig/arch/arm/mach-pxa/Makefile 2007-09-09 21:46:27.000000000 -0300 +++ linux-2.6.21/arch/arm/mach-pxa/Makefile 2007-09-09 21:46:27.000000000 -0300 @@ -27,6 +27,7 @@ obj-$(CONFIG_EZX_BP) += ezx-bp.o obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o obj-$(CONFIG_EZX_EMU) += ezx-emu.o +obj-$(CONFIG_EZX_EOC) += ezx-eoc.o # Support for blinky lights led-y := leds.o