From 82c0f44d02eebf2c0855dedbc4ee4b9820bd901a Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Wed, 8 Jun 2011 11:07:32 +0530 Subject: Stagging : AB5500 SIM interface Driver SIM Interface driver provides interface to configure various parameters of AB5500 SIM Level Shifter. Support provided are: Configure Pull up on sim lines Configure Operation Mode Notify Sim Insert/Extract Interrupt ST-Ericsson Linux next: 336280 ST-Ericsson ID: 341172 ST-Ericsson FOSS-OUT ID:STETL-FOSS-OUT-10242 Change-Id: I5ef4b92384ca4da0f96839afae7c7468f244978f Signed-off-by: Bibek Basu Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21582 Reviewed-by: QATEST Reviewed-by: Srinidhi KASAGAR --- drivers/staging/Kconfig | 10 ++ drivers/staging/Makefile | 1 + drivers/staging/ab5500_sim/Makefile | 1 + drivers/staging/ab5500_sim/ab5500-sim.c | 299 ++++++++++++++++++++++++++++++++ drivers/staging/ab5500_sim/sysfs-sim | 83 +++++++++ 5 files changed, 394 insertions(+) create mode 100644 drivers/staging/ab5500_sim/Makefile create mode 100644 drivers/staging/ab5500_sim/ab5500-sim.c create mode 100644 drivers/staging/ab5500_sim/sysfs-sim (limited to 'drivers/staging') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index d3600e8a64c..fefbc57c7cc 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,6 +24,16 @@ menuconfig STAGING if STAGING +config AB5500_SIM + bool "ST-Ericsson AB5500 SIM Interface driver" + depends on AB5500_CORE + help + SIM Interface driver provides interface to configure + various parameters of AB5550 SIM Level Shifter.Support provided are: + Configure Pull up on sim lines + Configure Operation Mode + Notify Sim Insert/Extract Interrupt + source "drivers/staging/tty/Kconfig" source "drivers/staging/generic_serial/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 8733f7d4cb1..464a2ac324c 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_CW1200) += cw1200/ obj-$(CONFIG_U8500_MMIO) += mmio/ obj-$(CONFIG_U8500_FLASH) += camera_flash/ obj-$(CONFIG_U8500_CM) += nmf-cm/ +obj-$(CONFIG_AB5500_SIM) += ab5500_sim/ diff --git a/drivers/staging/ab5500_sim/Makefile b/drivers/staging/ab5500_sim/Makefile new file mode 100644 index 00000000000..520717e4dd7 --- /dev/null +++ b/drivers/staging/ab5500_sim/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_AB5500_SIM) += ab5500-sim.o diff --git a/drivers/staging/ab5500_sim/ab5500-sim.c b/drivers/staging/ab5500_sim/ab5500-sim.c new file mode 100644 index 00000000000..788a7984a46 --- /dev/null +++ b/drivers/staging/ab5500_sim/ab5500-sim.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) ST Ericsson SA 2010 + * + * Sim Interface driver for AB5500 + * + * License Terms: GNU General Public License v2 + * Author: Bibek Basu + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USIM_SUP2_REG 0x13 +#define USIM_SUP_REG 0x14 +#define USIM_SIMCTRL_REG 0x17 +#define USIM_SIMCTRL2_REG 0x18 +#define USIM_USBUICC_REG 0x19 +#define USIM_USBUICC2_REG 0x20 +#define SIM_DAT_PULLUP_10K 0x0F +#define SIM_LDO_1_8V 1875000 +#define SIM_LDO_2_8V 2800000 +#define SIM_LDO_2_9V 2900000 + +enum shift { + SHIFT0, + SHIFT1, + SHIFT2, + SHIFT3, + SHIFT4, + SHIFT5, + SHIFT6, + SHIFT7, +}; + +enum mask { + MASK1 = 1, + MASK3 = 3, + MASK7 = 7, +}; + +enum sim_mode { + OFF_MODE, + LOW_PWR, + PWRCTRL, + FULL_PWR, +}; +/** + * struct ab5500_sim - ab5500 Sim Interface device information + * @dev: pointer to the structure device + * @lock: mutex lock + * @sim_int_status: Sim presence status + * @irq_base: Base of the two irqs + */ +struct ab5500_sim { + struct device *dev; + struct mutex lock; + bool sim_int_status; + u8 irq_base; +}; + +/* Exposure to the sysfs interface */ +int ab5500_sim_weak_pulldforce(struct device *dev, + struct device_attribute *attr, + const char *user_buf, size_t count) +{ + unsigned long user_val; + int err; + bool enable; + + err = strict_strtoul(user_buf, 0, &user_val); + if (err) + return -EINVAL; + enable = user_val ? true : false; + err = abx500_mask_and_set(dev, AB5500_BANK_SIM_USBSIM, + USIM_USBUICC2_REG, MASK1 << SHIFT5, user_val << SHIFT5); + if (err) + return -EINVAL; + return count; +} + +int ab5500_sim_load_sel(struct device *dev, + struct device_attribute *attr, + const char *user_buf, size_t count) +{ + unsigned long user_val; + int err; + bool enable; + + err = strict_strtoul(user_buf, 0, &user_val); + if (err) + return -EINVAL; + enable = user_val ? true : false; + err = abx500_mask_and_set(dev, AB5500_BANK_SIM_USBSIM, + USIM_USBUICC_REG, MASK1 << SHIFT1, user_val << SHIFT1); + if (err) + return -EINVAL; + return count; +} + +int ab5500_sim_mode_sel(struct device *dev, + struct device_attribute *attr, + const char *user_buf, size_t count) +{ + unsigned long user_val; + int err; + + err = strict_strtoul(user_buf, 0, &user_val); + if (err) + return -EINVAL; + err = abx500_mask_and_set(dev, AB5500_BANK_SIM_USBSIM, + USIM_SIMCTRL2_REG, MASK3 << SHIFT4, user_val << SHIFT4); + if (err) + return -EINVAL; + return count; +} + +int ab5500_sim_dat_pullup(struct device *dev, + struct device_attribute *attr, + const char *user_buf, size_t count) +{ + unsigned long user_val; + int err; + + err = strict_strtoul(user_buf, 0, &user_val); + if (err) + return -EINVAL; + err = abx500_mask_and_set(dev, AB5500_BANK_SIM_USBSIM, + USIM_SIMCTRL_REG, MASK7, user_val); + if (err) + return -EINVAL; + return count; +} + +int ab5500_sim_enable_pullup(struct device *dev, + struct device_attribute *attr, + const char *user_buf, size_t count) +{ + unsigned long user_val; + int err; + bool enable; + + err = strict_strtoul(user_buf, 0, &user_val); + if (err) + return -EINVAL; + enable = user_val ? true : false; + err = abx500_mask_and_set(dev, AB5500_BANK_SIM_USBSIM, + USIM_SIMCTRL_REG, MASK1 << SHIFT3, enable << SHIFT3); + if (err) + return -EINVAL; + return count; +} + +static ssize_t ab5500_simoff_int(struct device *dev, + struct device_attribute *devattr, char *user_buf) +{ + struct ab5500_sim *di = dev_get_drvdata(dev); + int len; + + mutex_lock(&di->lock); + len = sprintf(user_buf, "%d\n", di->sim_int_status); + mutex_unlock(&di->lock); + return len; +} + +static DEVICE_ATTR(enable_pullup, S_IWUSR, NULL, ab5500_sim_enable_pullup); +static DEVICE_ATTR(dat_pullup, S_IWUSR, NULL, ab5500_sim_dat_pullup); +static DEVICE_ATTR(mode_sel, S_IWUSR, NULL, ab5500_sim_mode_sel); +static DEVICE_ATTR(load_sel, S_IWUSR, NULL, ab5500_sim_load_sel); +static DEVICE_ATTR(weak_pulldforce, S_IWUSR, NULL, ab5500_sim_weak_pulldforce); +static DEVICE_ATTR(simoff_int, S_IRUGO, ab5500_simoff_int, NULL); + +static struct attribute *ab5500_sim_attributes[] = { + &dev_attr_enable_pullup.attr, + &dev_attr_dat_pullup.attr, + &dev_attr_mode_sel.attr, + &dev_attr_load_sel.attr, + &dev_attr_weak_pulldforce.attr, + &dev_attr_simoff_int.attr, + NULL +}; + +static const struct attribute_group ab5500sim_attr_grp = { + .attrs = ab5500_sim_attributes, +}; + +static irqreturn_t ab5500_sim_irq_handler(int irq, void *irq_data) +{ + struct platform_device *pdev = irq_data; + struct ab5500_sim *data = platform_get_drvdata(pdev); + + if (irq == data->irq_base) + data->sim_int_status = true; + else + data->sim_int_status = false; + sysfs_notify(&pdev->dev.kobj, NULL, "simoff_int"); + + return IRQ_HANDLED; +} + +static int __devexit ab5500_sim_remove(struct platform_device *pdev) +{ + struct ab5500_sim *di = platform_get_drvdata(pdev); + int irq = platform_get_irq_byname(pdev, "SIMOFF"); + + if (irq >= 0) { + free_irq(irq, di); + irq++; + free_irq(irq, di); + } + sysfs_remove_group(&pdev->dev.kobj, &ab5500sim_attr_grp); + platform_set_drvdata(pdev, NULL); + kfree(di); + + return 0; +} + +static int __devinit ab5500_sim_probe(struct platform_device *pdev) +{ + int ret = 0; + int irq; + struct ab5500_sim *di = + kzalloc(sizeof(struct ab5500_sim), GFP_KERNEL); + if (!di) + return -ENOMEM; + + dev_info(&pdev->dev, "ab5500_sim_driver PROBE\n"); + irq = platform_get_irq_byname(pdev, "SIMOFF"); + if (irq < 0) { + dev_err(&pdev->dev, "Get irq by name failed\n"); + return irq; + } + di->irq_base = irq; + di->dev = &pdev->dev; + mutex_init(&di->lock); + platform_set_drvdata(pdev, di); + /* sysfs interface to configure sim reg from user space */ + if (sysfs_create_group(&pdev->dev.kobj, &ab5500sim_attr_grp) < 0) { + dev_err(&pdev->dev, " Failed creating sysfs group\n"); + return -ENOMEM; + } + ret = request_threaded_irq(irq, NULL, ab5500_sim_irq_handler, + IRQF_NO_SUSPEND , "ab5500-sim", pdev); + if (ret < 0) { + dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret); + goto exit; + } + /* this is the contiguous irq for sim removal,falling edge */ + irq = irq + 1; + ret = request_threaded_irq(irq, NULL, ab5500_sim_irq_handler, + IRQF_NO_SUSPEND , "ab5500-sim", pdev); + if (ret < 0) { + dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret); + free_irq(--irq, di); + goto exit; + } + return ret; +exit: + sysfs_remove_group(&pdev->dev.kobj, &ab5500sim_attr_grp); + platform_set_drvdata(pdev, NULL); + kfree(di); + return ret; +} + +static struct platform_driver ab5500_sim_driver = { + .probe = ab5500_sim_probe, + .remove = __devexit_p(ab5500_sim_remove), + .driver = { + .name = "ab5500-sim", + .owner = THIS_MODULE, + }, +}; + +static int __init ab5500_sim_init(void) +{ + return platform_driver_register(&ab5500_sim_driver); +} + +static void __exit ab5500_sim_exit(void) +{ + platform_driver_unregister(&ab5500_sim_driver); +} + +module_init(ab5500_sim_init); +module_exit(ab5500_sim_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Bibek Basu"); +MODULE_ALIAS("platform:ab5500-sim"); +MODULE_DESCRIPTION("AB5500 sim interface driver"); diff --git a/drivers/staging/ab5500_sim/sysfs-sim b/drivers/staging/ab5500_sim/sysfs-sim new file mode 100644 index 00000000000..b809b21e39e --- /dev/null +++ b/drivers/staging/ab5500_sim/sysfs-sim @@ -0,0 +1,83 @@ +What: /sys/devices/platform/ab5500-core.0/ab5500-sim.4/ +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4 directory contains attributes + allowing the user space to check and configure ab5500 sim level + shifter interface caracteristics for communication to SIM card + +What: /sys/devices/.../enable_pullup +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4/enable_pullup attribute allows + the user space to configure if internal pull up in SIMIO lines + has to be enabled or disabled. For enabling write 1 to the file + and 0 for disabling + + +What: /sys/devices/.../dat_pullup +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4/dat_pullup attribute allows + the user space to configure the resistance value for internal + pull up in SIMIO lines. Following value can be written on the file + 0 SIM_DAT pull-up disabled + 1 SIM_DAT pull-up 4kOhm + 2 SIM_DAT pull-up 5kOhm + 3 SIM_DAT pull-up 6kOhm + 4 SIM_DAT pull-up 7kOhm + 5 SIM_DAT pull-up 8kOhm + 6 SIM_DAT pull-up 9kOhm + 7 SIM_DAT pull-up 10kOhm + +What: /sys/devices/.../mode_sel +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4/mode_sel attribute allows + the user space to configure the mode at which the level shifter + will work. Following value can be written on the file + 0 TG mode and LI mode off + 1 TG mode on + 2 LI mode on + 3 TG mode and LI mode off + +What: /sys/devices/.../load_sel +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4/load_sel attribute allows + the user space to configure the load on the USBUICC lines. + Following value can be written on the file. + 0 Data line load < 21pF + 1 Data line load 21-30pF + +What: /sys/devices/.../weak_pulldforce +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4/weak_pulldforce attribute allows + the user space to configure the weak pull down on the USBUICC lines. + Following value can be written on the file. + 0 USB-UICC data lines weak pull down active + 1 USB-UICC data lines weak pull down not active + +What: /sys/devices/.../simoff_int +Date: June 2011 +KernelVersion: 2.6.35 +Contact: Bibek Basu +Description: + The /sys/devices/.../ab5500-sim.4/simoff_int attribute allows + the user space to poll this file and get notified in case a sim + hot swap has happened. a zero means sim extracetd and a one means + inserted. + + -- cgit v1.2.3