/* * Copyright (C) ST-Ericsson SA 2010 * * Author: Rabin Vincent for ST-Ericsson * License terms: GNU General Public License (GPL), version 2 */ #define pr_fmt(fmt) "mop500-uib: " fmt #include #include #include #include #include #include #include #include #include #include "pins.h" #include "board-mop500.h" enum mop500_uib { STUIB, U8500UIB, U8500UIB_R3, NO_UIB, }; struct uib { const char *name; const char *option; void (*init)(void); }; static u8 type_of_uib = NO_UIB; static struct uib __initdata mop500_uibs[] = { [STUIB] = { .name = "ST-UIB", .option = "stuib", .init = mop500_stuib_init, }, [U8500UIB] = { .name = "U8500-UIB", .option = "u8500uib", .init = mop500_u8500uib_init, }, #ifdef CONFIG_TOUCHSCREEN_CYTTSP_SPI [U8500UIB_R3] = { .name = "U8500-UIBR3", .option = "u8500uibr3", .init = mop500_u8500uib_r3_init, }, #endif }; static struct uib __initdata *mop500_uib; static int __init mop500_uib_setup(char *str) { int i; for (i = 0; i < ARRAY_SIZE(mop500_uibs); i++) { struct uib *uib = &mop500_uibs[i]; if (!strcmp(str, uib->option)) { mop500_uib = uib; break; } } if (i == ARRAY_SIZE(mop500_uibs)) pr_err("invalid uib= option (%s)\n", str); return 1; } __setup("uib=", mop500_uib_setup); /* * The UIBs are detected after the I2C host controllers are registered, so * i2c_register_board_info() can't be used. */ void mop500_uib_i2c_add(int busnum, struct i2c_board_info const *info, unsigned n) { struct i2c_adapter *adap; struct i2c_client *client; int i; adap = i2c_get_adapter(busnum); if (!adap) { pr_err("failed to get adapter i2c%d\n", busnum); return; } for (i = 0; i < n; i++) { client = i2c_new_device(adap, &info[i]); if (!client) pr_err("failed to register %s to i2c%d\n", info[i].type, busnum); } i2c_put_adapter(adap); } static void __init __mop500_uib_init(struct uib *uib, const char *why) { pr_info("%s (%s)\n", uib->name, why); if (strcmp("stuib", uib->option) == 0) type_of_uib = STUIB; else if (strcmp("u8500uib", uib->option) == 0) type_of_uib = U8500UIB; else if (strcmp("u8500uibr3", uib->option) == 0) type_of_uib = U8500UIB_R3; uib->init(); } int uib_is_stuib(void) { return (type_of_uib == STUIB); } int uib_is_u8500uib(void) { return (type_of_uib == U8500UIB); } int uib_is_u8500uibr3(void) { return (type_of_uib == U8500UIB_R3); } #ifdef CONFIG_UX500_GPIO_KEYS static struct gpio_keys_button mop500_gpio_keys[] = { { .desc = "SFH7741 Proximity Sensor", .type = EV_SW, .code = SW_FRONT_PROXIMITY, .active_low = 0, .can_disable = 1, }, { .desc = "HED54XXU11 Hall Effect Sensor", .type = EV_SW, .code = SW_LID, /* FIXME arbitrary usage */ .active_low = 0, .can_disable = 1, } }; static struct regulator *gpio_keys_regulator; static int mop500_gpio_keys_activate(struct device *dev); static void mop500_gpio_keys_deactivate(struct device *dev); static struct gpio_keys_platform_data mop500_gpio_keys_data = { .buttons = mop500_gpio_keys, .nbuttons = ARRAY_SIZE(mop500_gpio_keys), .enable = mop500_gpio_keys_activate, .disable = mop500_gpio_keys_deactivate, }; static struct platform_device mop500_gpio_keys_device = { .name = "gpio-keys", .id = 0, .dev = { .platform_data = &mop500_gpio_keys_data, }, }; static int mop500_gpio_keys_activate(struct device *dev) { gpio_keys_regulator = regulator_get(&mop500_gpio_keys_device.dev, "vcc"); if (IS_ERR(gpio_keys_regulator)) { dev_err(&mop500_gpio_keys_device.dev, "no regulator\n"); return PTR_ERR(gpio_keys_regulator); } regulator_enable(gpio_keys_regulator); /* * Please be aware that the start-up time of the SFH7741 is * 120 ms and during that time the output is undefined. */ return 0; } static void mop500_gpio_keys_deactivate(struct device *dev) { if (!IS_ERR(gpio_keys_regulator)) { regulator_disable(gpio_keys_regulator); regulator_put(gpio_keys_regulator); } } static __init void mop500_gpio_keys_init(void) { struct ux500_pins *gpio_keys_pins = ux500_pins_get("gpio-keys.0"); if (gpio_keys_pins == NULL) { pr_err("gpio_keys: Fail to get pins\n"); return; } ux500_pins_enable(gpio_keys_pins); if (type_of_uib == U8500UIB_R3) mop500_gpio_keys[0].gpio = PIN_NUM(gpio_keys_pins->cfg[2]); else mop500_gpio_keys[0].gpio = PIN_NUM(gpio_keys_pins->cfg[0]); mop500_gpio_keys[1].gpio = PIN_NUM(gpio_keys_pins->cfg[1]); } #else static inline void mop500_gpio_keys_init(void) { } #endif /* add any platform devices here - TODO */ static struct platform_device *mop500_uib_platform_devs[] __initdata = { #ifdef CONFIG_UX500_GPIO_KEYS &mop500_gpio_keys_device, #endif }; /* * Detect the UIB attached based on the presence or absence of i2c devices. */ static int __init mop500_uib_init(void) { struct uib *uib = mop500_uibs; struct i2c_adapter *i2c0; struct i2c_adapter *i2c3; int ret; /* snowball and non u8500 cpus dont have uib */ if (!cpu_is_u8500() || machine_is_snowball()) return -ENODEV; i2c0 = i2c_get_adapter(0); if (!i2c0) { __mop500_uib_init(&mop500_uibs[STUIB], "fallback, could not get i2c0"); return -ENODEV; } /* U8500-UIB has the TC35893 at 0x44 on I2C0, the ST-UIB doesn't. */ ret = i2c_smbus_xfer(i2c0, 0x44, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_QUICK, NULL); i2c_put_adapter(i2c0); i2c3 = i2c_get_adapter(3); if (!i2c3) { __mop500_uib_init(&mop500_uibs[STUIB], "fallback, could not get i2c3"); return -ENODEV; } if (ret == 0) { ret = i2c_smbus_xfer(i2c3, 0x4B, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_QUICK, NULL); i2c_put_adapter(i2c3); if (ret == 0) uib = &mop500_uibs[U8500UIB]; else uib = &mop500_uibs[U8500UIB_R3]; } else { ret = i2c_smbus_xfer(i2c3, 0x5C, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_QUICK, NULL); i2c_put_adapter(i2c3); if (ret == 0) uib = &mop500_uibs[STUIB]; } __mop500_uib_init(uib, "detected"); mop500_gpio_keys_init(); platform_add_devices(mop500_uib_platform_devs, ARRAY_SIZE(mop500_uib_platform_devs)); return 0; } module_init(mop500_uib_init);