[PATCH 02/04] ARM i.MX25 Add SIM driver
Jaume Ribot
jaume at fqingenieria.es
Mon Jan 3 10:03:26 EST 2011
Hi Sascha,
On 03/01/2011 14:05, Sascha Hauer wrote:
> Hello Iban,
>
> On Mon, Jan 03, 2011 at 10:07:19AM +0100, FQ | Iban Cerro wrote:
>> This driver is slightly based on the Freescale original one, with several
>> code simplifications. We made specially emphasis in avoiding any ISO7816
>> code into the driver, which is not the right place to be. Driver mainly
>> works via ioctl to configure and then using read/write functions to
>> read/write smart cards.
>>
>> One important consideration (not clear in the User Manual from our point
>> of view) is that there exist two SIM modules into the MX25 core, both of
>> them in different memory position. This causes all accesses to SIM modules
>> must be done via SIM0. This differs from the way the User Manual explains
>> how to access the two different SIM modules, which seems is inherited from
>> the MX51 core.
> The following comments are mostly coding style related, running Lindent
> and checkpatch.pl on this patch seems to be a good start for improving
> this driver.
Thanks for comments and reviews. We will apply all recommendations and
we will resubmit patches, also with all identation issues solved.
> The main problem for pushing this driver to mainline is that you invent
> a i.MX specific smartcard API. This is not a good idea and probably not
> acceptable in mainline.
Regarding if this driver can fit into mainline, I agree that the kernel
is not the right place to contain a smartcard API. There are other
projects doing that quite well (muscle, opensc, ...). But in fact, the
idea of this driver is not to give a smartcard API but support the
I.MX25 SIM core, which is explicitly hardware dependant. IMHO, there is
no conceptual difference between this driver and any of the others
contained into plat-mxc/ directory. That's also why this driver has not
been placed into drivers/ directory. Maybe we can study to perform a
higher simplification of the driver, in order to remove any reminiscence
of smartcard API functions and only performing hardware (MX25) dependent
jobs .
>> Signed-off-by: Iban Cerro Galvez<iban at fqingenieria.es>
>> ---
>> arch/arm/plat-mxc/Kconfig | 7 +
>> arch/arm/plat-mxc/Makefile | 1 +
>> arch/arm/plat-mxc/include/mach/mxc_sim.h | 319 +++++++++++
>> arch/arm/plat-mxc/sim.c | 874
>> ++++++++++++++++++++++++++++++
> Your mailer breaks lines which means that other people can't apply this
> patch.
>
>> 4 files changed, 1201 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/plat-mxc/include/mach/mxc_sim.h
>> create mode 100644 arch/arm/plat-mxc/sim.c
>>
>> diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
>> index 389f217..7b16d0d 100644
>> --- a/arch/arm/plat-mxc/Kconfig
>> +++ b/arch/arm/plat-mxc/Kconfig
>> @@ -74,6 +74,13 @@ config MXC_PWM
>> help
>> Enable support for the i.MX PWM controller(s).
>>
>> +config MXC_SIM
>> + tristate "Enable SIM driver"
>> + select HAVE_SIM
>> + help
>> + Enable support for the i.MX SIM controller(s).
>> +
>> +
>> config MXC_DEBUG_BOARD
>> bool "Enable MXC debug board(for 3-stack)"
>> help
>> diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
>> index 5fd20e9..73073fb 100644
>> --- a/arch/arm/plat-mxc/Makefile
>> +++ b/arch/arm/plat-mxc/Makefile
>> @@ -12,6 +12,7 @@ obj-$(CONFIG_MXC_AVIC) += avic.o
>> obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
>> obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
>> obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
>> +obj-$(CONFIG_MXC_SIM) += sim.o
>> obj-$(CONFIG_MXC_PWM) += pwm.o
>> obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
>> obj-$(CONFIG_MXC_ULPI) += ulpi.o
>> diff --git a/arch/arm/plat-mxc/include/mach/mxc_sim.h
>> b/arch/arm/plat-mxc/include/mach/mxc_sim.h
>> new file mode 100644
>> index 0000000..74ff008
>> --- /dev/null
>> +++ b/arch/arm/plat-mxc/include/mach/mxc_sim.h
>> @@ -0,0 +1,319 @@
>> +/*
>> + * Copyright 2010-2011 FQ Ingenieria Electronica S.A.
>> + *
>> + * Adapted and simplify this driver to kernel mainline code style using
>> + * other drivers from Freescale
>> + * Jaume Ribot (jaume at fqingenieria.es)
>> + * Iban Cerro Galvez (iban at fqingenieria.es)
>> + */
>> +
>> +/*
>> + * 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.
>> + */
>> +
>> +/*!
>> + * @file mxc_sim.h
>> + *
>> + * @brief Driver for Freescale IMX SIM interface
>> + *
>> + */
>> +
>> +#ifndef MXC_SIM_INTERFACE_H
>> +#define MXC_SIM_INTERFACE_H
>> +
>> +#define SIM_DRIVER_VERSION 0x01
>> +
>> +/* Transmit and receive buffer sizes */
>> +#define SIM_XMT_BUFFER_SIZE 256
>> +#define SIM_RCV_BUFFER_SIZE 256
>> +
>> +/*BAUD_DIVISOR */
>> +#define SIM_DEFAULT_BAUD_DIV 372
>> +
>> +#define WRITE_TIMEOUT 1000
>> +#define READ_TIMEOUT 1000
>> +
>> +
>> +struct mxc_sim_platform_data {
>> + unsigned int clk_rate;
>> + char *clock_sim;
> Please do not pass clock names to drivers. Use clk_get(dev, id) instead.
>
>> + char *power_sim;
> This seems to be unused.
>
>> + int (*init)(struct platform_device *pdev);
>> + void (*exit)(void);
>> + unsigned int detect; /* 1 have detect pin, 0 not */
>> + unsigned int sim_number; /* 0 or 1 */
>> +};
>> +
>> +typedef struct {
>> + unsigned long addr;
>> + unsigned long data;
>> +} sim_reg;
> Do not typedef struct types, see Documentation/CodingStyle.
>
>> +
>> +/* Main SIM driver structure */
>> +typedef struct {
>> + /*SIM number 0, 1 */
>> + int sim_number;
>> + /* card inserted = 1, ATR received = 2, card removed = 0 */
>> + int present;
>> + /* current ATR or OPS state */
>> + int state;
>> + /* current power state */
>> + int power;
>> + /* error code occured during transfer */
>> + int errval;
>> + /* Clock id */
>> + struct clk *clk;
>> + /* on off clk*/
>> + uint8_t clk_flag;
>> + /* frequency of clk sim */
>> + uint32_t clk_sim;
>> + /* value of clk divisor*/
>> + int uart_div;
>> + /* IO map memory */
>> + struct resource *res;
>> + /* Mapped address */
>> + void __iomem *ioaddr; /* Mapped address */
>> + int ipb_irq; /* sim ipb IRQ num */
>> + int dat_irq; /* sim dat IRQ num */
>> + /* async notifier for card and ATR detection */
>> + struct fasync_struct *fasync;
>> + /* Platform specific data */
>> + struct mxc_sim_platform_data *plat_data;
>> +} sim_t;
> ditto
>
>> +
>> +/* ISO7816-3 protocols */
>> +#define SIM_PROTOCOL_T0 0
>> +#define SIM_PROTOCOL_T1 1
>> +
>> +/* Transfer types for SIM_IOCTL_XFER */
>> +#define SIM_XFER_TYPE_TPDU 0
>> +#define SIM_XFER_TYPE_PTS 1
>> +
>> +/* Interface power states */
>> +#define SIM_POWER_OFF 0
>> +#define SIM_POWER_ON 1
>> +
>> +/* Return values for SIM_IOCTL_GET_PRESENSE */
>> +#define SIM_PRESENT_REMOVED 0
>> +#define SIM_PRESENT_DETECTED 1
>> +#define SIM_PRESENT_OPERATIONAL 2
>> +
>> +/* Return values for SIM_IOCTL_GET_ERROR */
>> +#define SIM_OK 0
>> +#define SIM_E_ACCESS 1
>> +#define SIM_E_TPDUSHORT 2
>> +#define SIM_E_PTSEMPTY 3
>> +#define SIM_E_INVALIDXFERTYPE 4
>> +#define SIM_E_INVALIDXMTLENGTH 5
>> +#define SIM_E_INVALIDRCVLENGTH 6
>> +#define SIM_E_NACK 7
>> +#define SIM_E_TIMEOUT 8
>> +#define SIM_E_NOCARD 9
>> +#define SIM_E_PARAM_FI_INVALID 10
>> +#define SIM_E_PARAM_DI_INVALID 11
>> +#define SIM_E_PARAM_FBYD_WITHFRACTION 12
>> +#define SIM_E_PARAM_FBYD_NOTDIVBY8OR12 13
>> +#define SIM_E_PARAM_DIVISOR_RANGE 14
>> +#define SIM_E_MALLOC 15
>> +#define SIM_E_IRQ 16
>> +#define SIM_E_POWERED_ON 17
>> +#define SIM_E_POWERED_OFF 18
>> +
>> +/* ioctl encodings */
>> +#define SIM_IOCTL_BASE 0xc0
>> +#define SIM_IOCTL_VERSION _IOR(SIM_IOCTL_BASE, 1,unsigned char)
>> +#define SIM_IOCTL_POWER_ON _IO(SIM_IOCTL_BASE, 2)
>> +#define SIM_IOCTL_POWER_OFF _IO(SIM_IOCTL_BASE, 3)
>> +#define SIM_IOCTL_WARM_RESET _IO(SIM_IOCTL_BASE, 4)
>> +#define SIM_IOCTL_COLD_RESET _IO(SIM_IOCTL_BASE, 5)
>> +#define SIM_IOCTL_CLK_PORT _IOW(SIM_IOCTL_BASE, 6, int)
>> +#define SIM_IOCTL_RST_PORT _IOW(SIM_IOCTL_BASE, 7, int)
>> +#define SIM_IOCTL_VCC_PORT _IOW(SIM_IOCTL_BASE, 8, int)
>> +#define SIM_IOCTL_SET_CLK_SIM _IOW(SIM_IOCTL_BASE, 9, unsigned long)
>> +#define SIM_IOCTL_SET_CLK_DIV _IOW(SIM_IOCTL_BASE, 10, int)
>> +#define SIM_IOCTL_GET_REG _IOW(SIM_IOCTL_BASE, 11, sim_reg)
>> +#define SIM_IOCTL_SET_REG _IOW(SIM_IOCTL_BASE, 12, sim_reg)
>> +
>> +/* Interface character references */
>> +#define SIM_IFC_TXI(letter, number) (letter + number * 4)
>> +#define SIM_IFC_TA1 SIM_IFC_TXI(0, 0)
>> +#define SIM_IFC_TB1 SIM_IFC_TXI(0, 1)
>> +#define SIM_IFC_TC1 SIM_IFC_TXI(0, 2)
>> +#define SIM_IFC_TD1 SIM_IFC_TXI(0, 3)
>> +#define SIM_IFC_TA2 SIM_IFC_TXI(1, 0)
>> +#define SIM_IFC_TB2 SIM_IFC_TXI(1, 1)
>> +#define SIM_IFC_TC2 SIM_IFC_TXI(1, 2)
>> +#define SIM_IFC_TD2 SIM_IFC_TXI(1, 3)
>> +#define SIM_IFC_TA3 SIM_IFC_TXI(2, 0)
>> +#define SIM_IFC_TB3 SIM_IFC_TXI(2, 1)
>> +#define SIM_IFC_TC3 SIM_IFC_TXI(2, 2)
>> +#define SIM_IFC_TD3 SIM_IFC_TXI(2, 3)
>> +#define SIM_IFC_TA4 SIM_IFC_TXI(3, 0)
>> +#define SIM_IFC_TB4 SIM_IFC_TXI(3, 1)
>> +#define SIM_IFC_TC4 SIM_IFC_TXI(3, 2)
>> +#define SIM_IFC_TD4 SIM_IFC_TXI(3, 3)
>> +
>> +/* ATR and OPS states */
>> +#define SIM_STATE_REMOVED 0
>> +#define SIM_STATE_OPERATIONAL_IDLE 1
>> +#define SIM_STATE_OPERATIONAL_COMMAND 2
>> +#define SIM_STATE_OPERATIONAL_RESPONSE 3
>> +#define SIM_STATE_OPERATIONAL_STATUS1 4
>> +#define SIM_STATE_OPERATIONAL_STATUS2 5
>> +#define SIM_STATE_OPERATIONAL_PTS 6
>> +#define SIM_STATE_DETECTED_ATR_T0 7
>> +#define SIM_STATE_DETECTED_ATR_TS 8
>> +#define SIM_STATE_DETECTED_ATR_TXI 9
>> +#define SIM_STATE_DETECTED_ATR_THB 10
>> +#define SIM_STATE_DETECTED_ATR_TCK 11
>> +
>> +/* Definitions of the offset of the SIM hardware registers */
>> +#define PORT1_CNTL 0x00 /* 00 */
>> +#define SETUP 0x04 /* 04 */
>> +#define PORT1_DETECT 0x08 /* 08 */
>> +#define PORT1_XMT_BUF 0x0C /* 0c */
>> +#define PORT1_RCV_BUF 0x10 /* 10 */
>> +#define PORT0_CNTL 0x14 /* 14 */
>> +#define CNTL 0x18 /* 18 */
>> +#define CLK_PRESCALER 0x1C /* 1c */
>> +#define RCV_THRESHOLD 0x20 /* 20 */
>> +#define ENABLE 0x24 /* 24 */
>> +#define XMT_STATUS 0x28 /* 28 */
>> +#define RCV_STATUS 0x2C /* 2c */
>> +#define INT_MASK 0x30 /* 30 */
>> +#define PORTO_XMT_BUF 0x34 /* 34 */
>> +#define PORT0_RCV_BUF 0x38 /* 38 */
>> +#define PORT0_DETECT 0x3C /* 3c */
>> +#define DATA_FORMAT 0x40 /* 40 */
>> +#define XMT_THRESHOLD 0x44 /* 44 */
>> +#define GUARD_CNTL 0x48 /* 48 */
>> +#define OD_CONFIG 0x4C /* 4c */
>> +#define RESET_CNTL 0x50 /* 50 */
>> +#define CHAR_WAIT 0x54 /* 54 */
>> +#define GPCNT 0x58 /* 58 */
>> +#define DIVISOR 0x5C /* 5c */
>> +#define BWT 0x60 /* 60 */
>> +#define BGT 0x64 /* 64 */
>> +#define BWT_H 0x68 /* 68 */
>> +#define XMT_FIFO_STAT 0x6C /* 6c */
>> +#define RCV_FIFO_CNT 0x70 /* 70 */
>> +#define RCV_FIFO_WPTR 0x74 /* 74 */
>> +#define RCV_FIFO_RPTR 0x78 /* 78 */
> so 0x78 means 78, who would have guessed that? Please remove the comments.
>
>> +
>> +/* SIM port[0|1]_cntl register bits */
>> +#define SIM_PORT_CNTL_SFPD (1<<7)
>> +#define SIM_PORT_CNTL_3VOLT (1<<6)
>> +#define SIM_PORT_CNTL_SCSP (1<<5)
>> +#define SIM_PORT_CNTL_SCEN (1<<4)
>> +#define SIM_PORT_CNTL_SRST (1<<3)
>> +#define SIM_PORT_CNTL_STEN (1<<2)
>> +#define SIM_PORT_CNTL_SVEN (1<<1)
>> +#define SIM_PORT_CNTL_SAPD (1<<0)
>> +
>> +#define MX25_SIM_SETUP_P1_EN (1<<1) // Port 1 enabled
>> +#define MX25_SIM_SETUP_AMODE_EN (1<<0) // Alternate port enabled
> Please do not use C99 style comments.
>
>> +
>> +/* SIM od_config register bits */
>> +#define SIM_OD_CONFIG_OD_P1 (1<<1)
>> +#define SIM_OD_CONFIG_OD_P0 (1<<0)
>> +
>> +/* SIM enable register bits */
>> +#define SIM_ENABLE_XMTEN (1<<1)
>> +#define SIM_ENABLE_RCVEN (1<<0)
>> +
>> +/* SIM int_mask register bits */
>> +#define SIM_INT_MASK_RFEM (1<<13)
>> +#define SIM_INT_MASK_BGTM (1<<12)
>> +#define SIM_INT_MASK_BWTM (1<<11)
>> +#define SIM_INT_MASK_RTM (1<<10)
>> +#define SIM_INT_MASK_CWTM (1<<9)
>> +#define SIM_INT_MASK_GPCM (1<<8)
>> +#define SIM_INT_MASK_TDTFM (1<<7)
>> +#define SIM_INT_MASK_TFOM (1<<6)
>> +#define SIM_INT_MASK_XTM (1<<5)
>> +#define SIM_INT_MASK_TFEIM (1<<4)
>> +#define SIM_INT_MASK_ETCIM (1<<3)
>> +#define SIM_INT_MASK_OIM (1<<2)
>> +#define SIM_INT_MASK_TCIM (1<<1)
>> +#define SIM_INT_MASK_RIM (1<<0)
>> +
>> +/* SIM xmt_status register bits */
>> +#define SIM_XMT_STATUS_GPCNT (1<<8)
>> +#define SIM_XMT_STATUS_TDTF (1<<7)
>> +#define SIM_XMT_STATUS_TFO (1<<6)
>> +#define SIM_XMT_STATUS_TC (1<<5)
>> +#define SIM_XMT_STATUS_ETC (1<<4)
>> +#define SIM_XMT_STATUS_TFE (1<<3)
>> +#define SIM_XMT_STATUS_XTE (1<<0)
>> +
>> +/* SIM rcv_status register bits */
>> +#define SIM_RCV_STATUS_BGT (1<<11)
>> +#define SIM_RCV_STATUS_BWT (1<<10)
>> +#define SIM_RCV_STATUS_RTE (1<<9)
>> +#define SIM_RCV_STATUS_CWT (1<<8)
>> +#define SIM_RCV_STATUS_CRCOK (1<<7)
>> +#define SIM_RCV_STATUS_LRCOK (1<<6)
>> +#define SIM_RCV_STATUS_RDRF (1<<5)
>> +#define SIM_RCV_STATUS_RFD (1<<4)
>> +#define SIM_RCV_STATUS_RFE (1<<1)
>> +#define SIM_RCV_STATUS_OEF (1<<0)
>> +
>> +/* SIM cntl register bits */
>> +#define SIM_CNTL_BWTEN (1<<15)
>> +#define SIM_CNTL_XMT_CRC_LRC (1<<14)
>> +#define SIM_CNTL_CRCEN (1<<13)
>> +#define SIM_CNTL_LRCEN (1<<12)
>> +#define SIM_CNTL_CWTEN (1<<11)
>> +#define SIM_CNTL_SAMPLE12 (1<<4)
>> +#define SIM_CNTL_ONACK (1<<3)
>> +#define SIM_CNTL_ANACK (1<<2)
>> +#define SIM_CNTL_ICM (1<<1)
>> +#define SIM_CNTL_GPCNT_CLK_SEL(x) ((x&0x03)<<9)
> Please add some spacing here, like this: ((x& 0x3)<< 9)
> See Documentation/CodingStyle for more information.
> Also, there are braces missing around x, it should be:
>
> (((x)& 0x3)<< 9)
>
>> +#define SIM_CNTL_GPCNT_CLK_SEL_MASK (0x03<<9)
>> +#define SIM_CNTL_BAUD_SEL(x) ((x&0x07)<<6)
>> +#define SIM_CNTL_BAUD_SEL_MASK (0x07<<6)
>> +
>> +/* SIM rcv_threshold register bits */
>> +#define SIM_RCV_THRESHOLD_RTH(x) ((x&0x0f)<<9)
>> +#define SIM_RCV_THRESHOLD_RTH_MASK (0x0f<<9)
>> +#define SIM_RCV_THRESHOLD_RDT(x) ((x&0x1ff)<<0)
>> +#define SIM_RCV_THRESHOLD_RDT_MASK (0x1ff<<0)
>> +
>> +/* SIM xmt_threshold register bits */
>> +#define SIM_XMT_THRESHOLD_XTH(x) ((x&0x0f)<<4)
>> +#define SIM_XMT_THRESHOLD_XTH_MASK (0x0f<<4)
>> +#define SIM_XMT_THRESHOLD_TDT(x) ((x&0x0f)<<0)
>> +#define SIM_XMT_THRESHOLD_TDT_MASK (0x0f<<0)
>> +
>> +/* SIM guard_cntl register bits */
>> +#define SIM_GUARD_CNTL_RCVR11 (1<<8)
>> +#define SIM_GIARD_CNTL_GETU(x) (x&0xff)
>> +#define SIM_GIARD_CNTL_GETU_MASK (0xff)
>> +
>> +/* SIM port[0|]_detect register bits */
>> +#define SIM_PORT_DETECT_SPDS (1<<3)
>> +#define SIM_PORT_DETECT_SPDP (1<<2)
>> +#define SIM_PORT_DETECT_SDI (1<<1)
>> +#define SIM_PORT_DETECT_SDIM (1<<0)
>> +
>> +/* SIM XMT_FIFO_STAT*/
>> +#define SIM_XMT_FIFO_XMT_CNT_MASK (0x0f<<8)
>> +#define SIM_XMT_FIFO_XMT_WPTR_MASK (0x0f<<4)
>> +#define SIM_XMT_FIFO_XMT_RPTR_MASK (0x0f<<0)
>> +
>> +/* SIM PORT_RCV_BUF */
>> +#define PORT_RCV_BUF_PE (1<<8)
>> +#define PORT_RCV_BUF_FE (1<<9)
>> +#define PORT_RCV_BUF_CWT (1<<10)
>> +/* SIM RESET_CNTL */
>> +#define SIM_RESET_CNTL_DBUG (1<<6)
>> +#define SIM_RESET_CNTL_STOP (1<<5)
>> +#define SIM_RESET_CNTL_DOZE (1<<4)
>> +#define SIM_RESET_CNTL_KILL_CLOCK (1<<3)
>> +#define SIM_RESET_CNTL_SOFT_RST (1<<2)
>> +#define SIM_RESET_CNTL_FLUSH_XMT (1<<1)
>> +#define SIM_RESET_CNTL_FLUSH_RCV (1<<0)
>> +/* END of REGS definitions */
>> +#endif
>> diff --git a/arch/arm/plat-mxc/sim.c b/arch/arm/plat-mxc/sim.c
>> new file mode 100644
>> index 0000000..7af073c
>> --- /dev/null
>> +++ b/arch/arm/plat-mxc/sim.c
>> @@ -0,0 +1,874 @@
>> +/*
>> + * Copyright 2010-2011 FQ Ingenieria Electronica S.A.
>> + *
>> + * Adapted and simplify this driver to kernel mainline code style using
>> + * other drivers from Freescale
>> + * Jaume Ribot (jaume at fqingenieria.es)
>> + * Iban Cerro Galvez (iban at fqingenieria.es)
>> + */
>> +
>> +/*
>> + * 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.
>> + */
>> +
>> +/*!
>> + * @file mxc_sim.c
>> + *
>> + * @brief Driver for Freescale IMX SIM interface
>> + *
>> + */
>> +
>> +#include<linux/module.h>
>> +#include<linux/ioport.h>
>> +#include<linux/kernel.h>
>> +#include<linux/delay.h>
>> +
>> +#include<linux/sched.h>
>> +#include<linux/io.h>
>> +#include<linux/interrupt.h>
>> +#include<linux/poll.h>
>> +#include<linux/miscdevice.h>
>> +#include<linux/clk.h>
>> +#include<linux/types.h>
>> +#include<linux/platform_device.h>
>> +#include<linux/slab.h>
>> +
>> +#include<asm/io.h>
>> +#include<mach/hardware.h>
>> +#include<mach/mxc_sim.h>
>> +
>> +#define DRIVER_NAME "mxc_sim"
>> +#define SIM1_DEV_NAME "mxc_sim_0"
>> +#define SIM2_DEV_NAME "mxc_sim_1"
>> +
>> +static struct miscdevice sim_dev;
>> +
>> +#define sim_debug(fmt, ...) \
>> + printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
> Please do not define your own debug functions. dev_dbg is the weapon of
> choice here.
>
>> +
>> +
>> +/* Function: sim_clear_ports
>> + *
>> + * Description: function to unset reset, Vcc_enable or Clk_enable
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + * uint32_t value value to set port
>> + */
>> +static void sim_clear_ports(sim_t *sim, uint32_t value)
>> +{
>> + uint32_t reg_data;
>> + void __iomem *addr;
>> +
>> +#if defined(CONFIG_SOC_IMX25)
>> + if (cpu_is_mx25()) {
>> + addr = sim->ioaddr + PORT0_CNTL;
>> + }
> broken indention.
>
>> +#else
>> + if (sim->sim_number ==0)
>> + addr = sim->ioaddr + PORT0_CNTL;
>> + else
>> + addr = sim->ioaddr + PORT1_CNTL;
>> +#endif
> This #ifdef looks wrong here. The idea is to make the driver independent
> of compile time options. Now with this ifdef, if i.MX25 is enabled, it
> won't be working on any other SoC.
>
>> +
>> + reg_data = __raw_readl(addr);
>> + reg_data&= ~value;
>> + __raw_writel(reg_data, addr);
>> +}
>> +
>> +
>> +/* Function: sim_set_ports
>> + *
>> + * Description: function to set Reset, Vcc enable or Clk_enabble
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + * uint32_t value value to set port
>> + */
>> +static void sim_set_ports(sim_t *sim, uint32_t value)
>> +{
>> + uint32_t reg_data;
>> + void __iomem *addr;
>> +
>> +#if defined(CONFIG_SOC_IMX25)
>> + if (cpu_is_mx25()) {
>> + addr = sim->ioaddr + PORT0_CNTL;
>> + }
>> +#else
>> + if (sim->sim_number ==0)
>> + addr = sim->ioaddr + PORT0_CNTL;
>> + else
>> + addr = sim->ioaddr + PORT1_CNTL;
>> +#endif
>> +
>> + reg_data = __raw_readl(addr);
>> + reg_data |= value;
>> + __raw_writel(reg_data, addr);
>> +
>> +}
>> +
>> +
>> +/* Function: sim_power_on
>> + *
>> + * Description: run the power on sequence. Follow sequence explained in
>> RM 39.5
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +
>> +static void sim_power_on(sim_t *sim)
>> +{
>> + uint32_t reg_data;
>> +
>> + // Power on sequence
> This comment is not very useful.
>
>> + sim_debug("%s Powering on the sim port.\n", __func__);
>> +
>> + // Enable Vcc enable port
>> + sim_set_ports(sim, SIM_PORT_CNTL_SVEN);
>> + msleep(10);//TODO: adjust this delay
>> +
>> + // Enable CLK enable Port
>> + sim_set_ports(sim, SIM_PORT_CNTL_SCEN);
>> + msleep(10);//TODO: adjust this delay
>> +
>> + // Configure RCV parameters
>> + reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(1);
>> + __raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
>> + __raw_writel(SIM_RCV_STATUS_RDRF, sim->ioaddr + RCV_STATUS);
>> +
>> + //Configure int
>> + reg_data = __raw_readl(sim->ioaddr + INT_MASK);
>> + reg_data&= ~SIM_INT_MASK_RIM;
>> + __raw_writel(reg_data, sim->ioaddr + INT_MASK);
>> +
>> + //Duplicate in function sim_start
>> + __raw_writel(31, sim->ioaddr + DIVISOR);
>> + reg_data = __raw_readl(sim->ioaddr + CNTL);
>> + reg_data |= SIM_CNTL_SAMPLE12;
>> + __raw_writel(reg_data, sim->ioaddr + CNTL);
>> +
>> + // Enable RCV
>> + reg_data = __raw_readl(sim->ioaddr + ENABLE);
>> + reg_data |= SIM_ENABLE_RCVEN;
>> + __raw_writel(reg_data, sim->ioaddr + ENABLE);
>> +
>> + // Enable RST
>> + sim_set_ports(sim, SIM_PORT_CNTL_SRST);
>> + msleep(10);//TODO: adjust this delay
>> +
>> + sim->power = SIM_POWER_ON;
>> +
>> +};
>> +
>> +/* Function: sim_power_off
>> + *
>> + * Description: run the power off sequence
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +
>> +static void sim_power_off(sim_t *sim)
>> +{
>> + uint32_t reg_data;
>> +
>> + sim_debug("%s entering.\n", __func__);
>> + /* sim_power_off sequence */
>> +
>> + //disable clk
>> + sim_clear_ports(sim, SIM_PORT_CNTL_SCEN);
>> +
>> + reg_data = __raw_readl(sim->ioaddr + ENABLE);
>> + reg_data&= ~SIM_ENABLE_RCVEN;
>> + __raw_writel(reg_data, sim->ioaddr + ENABLE);
>> +
>> + reg_data = __raw_readl(sim->ioaddr + INT_MASK);
>> + reg_data |= SIM_INT_MASK_RIM;
>> + __raw_writel(reg_data, sim->ioaddr + INT_MASK);
>> +
>> + __raw_writel(0, sim->ioaddr + RCV_THRESHOLD);
>> +
>> + //Disable RST
>> + sim_clear_ports(sim, SIM_PORT_CNTL_SRST);
>> + //Disable Vcc enable port
>> + sim_clear_ports(sim, SIM_PORT_CNTL_SVEN);
>> +
>> + sim->power = SIM_POWER_OFF;
>> +};
>> +
>> +/* Function: sim_set_clk_sim
>> + *
>> + * Description: Set CLK SIM frequency
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +uint32_t sim_set_clk_sim(sim_t *sim)
>> +{
>> + uint32_t clk_rate, clk_div = 0;
>> + // get ipg_clk
>> + clk_rate = clk_get_rate(sim->clk);
>> + // calcule divisor
>> + clk_div = clk_rate / sim->clk_sim;
>> + if (clk_rate % sim->clk_sim)
>> + clk_div++;
>> + //write divisor
>> + __raw_writel(clk_div, sim->ioaddr + CLK_PRESCALER);
>> + //calculate real Value
>> + clk_rate =clk_rate/clk_div;
>> +
>> + sim_debug("%s prescaler is 0x%x.\n", __func__, clk_div);
>> + sim_debug("Clk = %d Hz\n", clk_rate);
>> +
>> + return clk_rate;
>> +}
>> +
>> +/* Function: sim_set_clk_uart_divisor
>> + *
>> + * Description: Set SIM Uart divisor frequency
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +int sim_set_clk_uart_divisor(sim_t *sim)
>> +{
>> + uint32_t reg, divisor;
>> +
>> + //ajust baud_sel -> divisor register
> s/ajust/adjust/
>
>> + reg = __raw_readl(sim->ioaddr + CNTL);
>> + //ajust sample 12
>> + if ((sim->uart_div % 12) == 0)
>> + {
> See Documentaion/CodingStyle for placing braces.
>
>> + reg |= SIM_CNTL_SAMPLE12;
>> + divisor=sim->uart_div/12;
>> + }
>> + else if ((sim->uart_div % 8) == 0)
>> + {
>> + reg&= ~SIM_CNTL_SAMPLE12;
>> + divisor=sim->uart_div/8;
>> + }
>> + else
>> + {
>> + sim_debug("%s no valid divisor \n", __func__);
>> + return -1;
>> + }
>> + // put 111 in baud_sel for use Divisor register
>> + reg |= SIM_CNTL_BAUD_SEL(7);
>> + __raw_writel(reg, sim->ioaddr + CNTL);
>> + //ajust Divisor register
>> + __raw_writel(divisor, sim->ioaddr + DIVISOR );
>> + sim_debug("%s divisor is %d.\n", __func__, sim->uart_div);
>> +
>> + return 0;
>> +}
>> +
>> +
>> +
>> +/* Function: sim_start
>> + *
>> + * Description: ramp up the SIM interface.
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +static void sim_start(sim_t *sim)
>> +{
>> + uint32_t reg_data = 0;
>> +
>> + sim_debug("%s entering.\n", __func__);
>> + // Configuring SIM for Operation
>> + // Adjust XMT thresholds (no NACK and 4 bytes or less to activate TDTF bit
>> + reg_data = SIM_XMT_THRESHOLD_XTH(0) | SIM_XMT_THRESHOLD_TDT(4);
>> + __raw_writel(reg_data, sim->ioaddr + XMT_THRESHOLD);
>> + // Enable SIM port N and alternate port disabled -> Only applies to MX51
>> + // Always eanble port 0,
>> +
>> + // Always enable port 0 -> Duplicated SIM core
>> + __raw_writel(0x00, sim->ioaddr + SETUP);
>> +
>> + // Adjust clock divider in function of platform definitions
>> + // 66.5 / 5 -> 13.5 -> 14 (4.75MHZ initial frequency)
>> + sim->clk_sim = sim->plat_data->clk_rate;
>> + sim_set_clk_sim(sim);
>> +
>> + // Adjust Control register
>> + reg_data = __raw_readl(sim->ioaddr + CNTL);
>> + reg_data |= SIM_CNTL_ANACK | SIM_CNTL_ICM;
>> + __raw_writel(reg_data, sim->ioaddr + CNTL);
>> +
>> + // Adjust BAUD divider
>> + sim->uart_div=SIM_DEFAULT_BAUD_DIV;
>> + sim_set_clk_uart_divisor(sim);
>> +
>> + // Adjust Open Drain in Port 0 XMT configuration register
>> + reg_data = __raw_readl(sim->ioaddr + OD_CONFIG);
>> + reg_data |= SIM_OD_CONFIG_OD_P0 | SIM_OD_CONFIG_OD_P1;
>> + __raw_writel(reg_data, sim->ioaddr + OD_CONFIG);
>> +
>> + // Adjust Port 0
>> + reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
>> + reg_data |= SIM_PORT_CNTL_3VOLT | SIM_PORT_CNTL_STEN;
>> + __raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
>> +
>> + // Since there is no PD0 layout on MX51, assume that there is a SIM card
>> in slot defaulty.
>> + if (0 == (sim->plat_data->detect)) {
>> + reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
>> + reg_data |= SIM_PORT_DETECT_SPDS;
>> + __raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
>> + sim->present = SIM_PRESENT_DETECTED;
>> + }
>> +
>> + // FQ enable SIM present on the future
>> + if (sim->present == SIM_PRESENT_DETECTED)
>> + sim_power_on(sim);
>> +
>> +};
>> +
>> +/* Function: sim_stop
>> + *
>> + * Description: shut down the SIM interface
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +
>> +static void sim_stop(sim_t *sim)
>> +{
>> + sim_debug("%s entering.\n", __func__);
>> + __raw_writel(0, sim->ioaddr + SETUP);
>> + __raw_writel(0, sim->ioaddr + ENABLE);
>> + __raw_writel(0, sim->ioaddr + PORT0_CNTL);
>> + __raw_writel(SIM_CNTL_ANACK | SIM_CNTL_ICM, sim->ioaddr + CNTL);
>> + __raw_writel(0, sim->ioaddr + CLK_PRESCALER);
>> + __raw_writel(0, sim->ioaddr + SETUP);
>> + __raw_writel(0, sim->ioaddr + OD_CONFIG);
>> + __raw_writel(0, sim->ioaddr + XMT_THRESHOLD);
>> + //Clear XMT_STATUS
>> + __raw_writel( SIM_XMT_STATUS_TDTF | SIM_XMT_STATUS_TC |
>> + SIM_XMT_STATUS_ETC | SIM_XMT_STATUS_TFE , sim->ioaddr +
>> XMT_STATUS);
>> + //Enable SOFT_RESET
>> + __raw_writel(SIM_RESET_CNTL_SOFT_RST , sim->ioaddr + RESET_CNTL);
>> + mdelay(1);//TODO: adjust this delay
>> +};
>> +
>> +/* Function: sim_data_reset
>> + *
>> + * Description: reset a SIM structure to default values
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +
>> +static void sim_data_reset(sim_t *sim)
>> +{
>> + sim->present = SIM_PRESENT_REMOVED;
>> + sim->state = SIM_STATE_REMOVED;
>> + sim->power = SIM_POWER_OFF;
>> + sim->errval = SIM_OK;
>> +};
>> +
>> +/* Function: sim_cold_reset
>> + *
>> + * Description: cold reset the SIM interface, including card
>> + * power down and interface hardware reset.
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +
>> +static void sim_cold_reset(sim_t *sim)
>> +{
>> + sim_debug("%s entering.\n", __func__);
>> + if (sim->present != SIM_PRESENT_REMOVED) {
>> + sim_power_off(sim);
>> + sim_stop(sim);
>> + sim_data_reset(sim);
>> + sim->state = SIM_STATE_DETECTED_ATR_T0;
>> + sim->present = SIM_PRESENT_DETECTED;
>> + msleep(50);//TODO: adjust this delay
>> + sim_start(sim);
>> + sim_power_on(sim);
>> + };
>> +};
>> +
>> +/* Function: sim_warm_reset
>> + *
>> + * Description: warm reset the SIM interface: just invoke the
>> + * reset signal and reset the SIM structure for the interface.
>> + *
>> + * Parameters:
>> + * sim_t* sim pointer to SIM device handler
>> + */
>> +
>> +static void sim_warm_reset(sim_t *sim)
>> +{
>> + sim_debug("%s entering.\n", __func__);
>> + if (sim->present != SIM_PRESENT_REMOVED) {
>> + sim_set_ports(sim,SIM_PORT_CNTL_SRST);
>> + sim_data_reset(sim);
>> + msleep(50);//TODO: adjust this delay
>> + sim_clear_ports(sim,SIM_PORT_CNTL_SRST);
>> +
>> + };
>> +};
>> +
>> +/* Function: sim_ioctl
>> + *
>> + * Description: handle ioctl calls
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static long sim_ioctl(struct file *file, unsigned int cmd, unsigned long
>> arg)
>> +{
>> + int ret=0, value=-1;
>> + unsigned long real_freq;
>> + unsigned char version = SIM_DRIVER_VERSION;
>> + sim_t *sim = (sim_t *) file->private_data;
>> + sim_reg s_reg = {0,0};
>> +
>> + sim_debug("%s cmd %d \n", __func__, cmd);
>> + switch (cmd) {
>> + sim_debug("ioctl cmd %d is issued...\n", cmd);
>> +
>> + case SIM_IOCTL_VERSION:
>> + sim_debug("ioctl cmd SIM_IOCTL_VERSION\n");
>> + ret = copy_to_user((unsigned char *) arg,&version,
>> + sizeof(unsigned char));
>> + break;
>> +
>> + case SIM_IOCTL_POWER_ON:
>> + sim_debug("ioctl cmd SIM_IOCTL_POWER_ON\n");
>> + if (sim->power == SIM_POWER_ON) {
>> + ret = -SIM_E_POWERED_ON;
>> + break;
>> + };
>> + sim_power_on(sim);
>> + break;
>> +
>> + case SIM_IOCTL_POWER_OFF:
>> + sim_debug("ioctl cmd SIM_IOCTL_POWER_OFF\n");
>> + if (sim->power == SIM_POWER_OFF) {
>> + ret = -SIM_E_POWERED_OFF;
>> + break;
>> + };
>> + sim_power_off(sim);
>> + break;
>> +
>> + case SIM_IOCTL_COLD_RESET:
>> + sim_debug("ioctl cmd SIM_IOCTL_COLD_RESET\n");
>> + if (sim->power == SIM_POWER_OFF) {
>> + ret = -SIM_E_POWERED_OFF;
>> + break;
>> + };
>> + sim_cold_reset(sim);
>> + break;
>> +
>> + case SIM_IOCTL_WARM_RESET:
>> + sim_debug("ioctl cmd SIM_IOCTL_WARM_RESET\n");
>> + sim_warm_reset(sim);
>> + if (sim->power == SIM_POWER_OFF) {
>> + ret = -SIM_E_POWERED_OFF;
>> + break;
>> + };
>> + break;
>> +
>> + case SIM_IOCTL_CLK_PORT:
>> + sim_debug("ioctl cmd SIM_IOCTL_CLK_PORT\n");
>> + ret = copy_from_user(&value, (int *) arg,
>> + sizeof(int));
>> + if (value == 0)
>> + sim_set_ports(sim, SIM_PORT_CNTL_SCEN);
>> + else
>> + sim_clear_ports(sim, SIM_PORT_CNTL_SCEN);
>> + break;
>> +
>> + case SIM_IOCTL_RST_PORT:
>> + sim_debug("ioctl cmd SIM_IOCTL_RST_PORT\n");
>> + ret = copy_from_user(&value, (int *) arg,
>> + sizeof(int));
>> + if (value == 0)
>> + sim_set_ports(sim, SIM_PORT_CNTL_SRST);
>> + else
>> + sim_clear_ports(sim, SIM_PORT_CNTL_SRST);
>> + break;
>> +
>> + case SIM_IOCTL_VCC_PORT:
>> + sim_debug("ioctl cmd SIM_IOCTL_VCC_PORT\n");
>> + ret = copy_from_user(&value, (int *) arg,
>> + sizeof(int));
>> + if (value == 0)
>> + sim_set_ports(sim, SIM_PORT_CNTL_SVEN);
>> + else
>> + sim_clear_ports(sim, SIM_PORT_CNTL_SVEN);
>> + break;
>> +
>> + case SIM_IOCTL_SET_CLK_SIM:
>> + sim_debug("ioctl cmd SIM_IOCTL_SET_CLK_SIM\n");
>> + ret = copy_from_user(&real_freq, (unsigned long *) arg,
>> + sizeof(unsigned long));
>> + if (sim->clk_sim> 0)
>> + {
>> + sim->clk_sim = real_freq;
>> + real_freq = sim_set_clk_sim(sim);
>> + }
>> + else
>> + {
>> + sim_debug("Invalid Freq. %lu Hz\n",real_freq );
>> + real_freq = -1;
>> + }
>> + ret = copy_to_user((unsigned long *) arg,&real_freq,
>> + sizeof(unsigned long));
>> + break;
>> +
>> + case SIM_IOCTL_SET_CLK_DIV:
>> + sim_debug("ioctl cmd SIM_IOCTL_SET_CLK_DIV\n");
>> + ret = copy_from_user(&value, (int *) arg,
>> + sizeof(int));
>> + if (sim->uart_div> 0)
>> + {
>> + sim->uart_div = value;
>> + ret = sim_set_clk_uart_divisor(sim);
>> + }
>> + else
>> + {
>> + sim_debug("Invalid DIV. %d\n",value);
>> + }
>> + break;
>> +
>> + /*debug register*/
>> + case SIM_IOCTL_GET_REG:
>> + sim_debug("ioctl cmd SIM_IOCTL_GET_REG\n");
>> + ret = copy_from_user(&s_reg, (sim_reg *) arg, sizeof(sim_reg));
>> + s_reg.data =(unsigned long) __raw_readl(s_reg.addr);
>> + ret = copy_to_user((sim_reg *) arg,&s_reg, sizeof(sim_reg));
>> + break;
>> +
>> + case SIM_IOCTL_SET_REG:
>> + sim_debug("ioctl cmd SIM_IOCTL_SET_REG\n");
>> + ret = copy_from_user(&s_reg, (sim_reg *) arg, sizeof(sim_reg));
>> + __raw_writel( (uint32_t) s_reg.data, sim->ioaddr + s_reg.addr);
>> + break;
>> + };
>> +
>> + return ret;
>> +};
>> +
>> +/* Function: sim_write
>> + *
>> + * Description: handle write calls
>> + *
>> + * Parameters: OS specific
>> + */
>> +static ssize_t sim_write(struct file *file, const char *user_buf,
>> + size_t count, loff_t *ppos)
>> +{
>> + int ret=0, i;
>> + uint32_t reg_data=0;
>> + sim_t *sim = (sim_t *) file->private_data;
>> + char write_buffer[SIM_XMT_BUFFER_SIZE];
>> + int timeout;
>> +
>> + sim_debug("%s entering.\n", __func__);
>> +
>> + ret = copy_from_user(write_buffer, user_buf,count);
> broken indention.
>
>> + if (ret)
>> + return -EFAULT;
>> +
>> + //start XMT
>> + reg_data = __raw_readl(sim->ioaddr + ENABLE);
>> + reg_data |= SIM_ENABLE_XMTEN;
>> + __raw_writel(reg_data, sim->ioaddr + ENABLE);
>> +
>> + for (i=0; i< count; i++)
>> + {
>> + //transmit 1 Byte
>> + __raw_writel( write_buffer[i],sim->ioaddr + PORT1_XMT_BUF );
>> + sim_debug( "TX = %02x\n", write_buffer[i] );
>> +
>> + // wait write 1 Byte TODO: interupts
>> + timeout= WRITE_TIMEOUT;
>> + do {
>> + reg_data = __raw_readl( sim->ioaddr + XMT_FIFO_STAT );
>> + reg_data = ( reg_data&& SIM_XMT_FIFO_XMT_CNT_MASK )>> 8;
>> + sim_debug("wait write, timeout = %d", timeout );
>> + timeout--;
>> + }while ( reg_data> 0&& timeout != 0 );
> broken indention.
>
>> + }
>> +
>> + //disable write
>> + reg_data = __raw_readl( sim->ioaddr + ENABLE );
>> + reg_data&= ~SIM_ENABLE_XMTEN;
>> + __raw_writel( reg_data, sim->ioaddr + ENABLE );
>> +
>> + return i;
>> +};
>> +
>> +/* Function: sim_read
>> + *
>> + * Description: handle read calls
>> + *
>> + * Parameters: OS specific
>> + */
>> +static ssize_t sim_read(struct file *file, char *user_buf,
>> + size_t count, loff_t *ppos)
>> +{
>> + int ret=0;
>> + char read_buffer[SIM_RCV_BUFFER_SIZE];
>> + sim_t *sim = (sim_t *) file->private_data;
>> + int i=0;
>> + int timeout = READ_TIMEOUT;
>> +
>> + sim_debug("%s entering.\n", __func__);
>> +
>> + while (__raw_readl(sim->ioaddr + RCV_FIFO_CNT) != 0&& i< count&&
>> timeout> 0 ) {
>> + uint32_t data;
>> + data = __raw_readl(sim->ioaddr + PORT1_RCV_BUF);
>> + sim_debug("RX = %02x\n", data);
>> + //detect parity ERROR or FRAME ERROR or CWT ERROR
>> + if ( data& (PORT_RCV_BUF_PE | PORT_RCV_BUF_FE | PORT_RCV_BUF_CWT ) )
>> + {
>> + printk(KERN_ERR "ERROR READ !\n");
>> + return IRQ_HANDLED;
>> + }
>> + else{
>> + read_buffer[i] = (char) data;
>> + i++;
>> + }
>> + timeout--;
>> + };
>> + ret = copy_to_user(user_buf, read_buffer,i);
>> + if (ret)
>> + return -EFAULT;
>> +
>> + return i;
>> +}
>> +
>> +
>> +/* Function: sim_open
>> + *
>> + * Description: ramp up interface when being opened
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static int sim_open(struct inode *inode, struct file *file)
>> +{
>> + int errval = SIM_OK;
>> +
>> + sim_t *sim = dev_get_drvdata(sim_dev.parent);
>> + file->private_data = sim;
>> +
>> + sim_debug("%s entering.\n", __func__);
>> + if (!sim->ioaddr) {
>> + errval = -ENOMEM;
>> + return errval;
>> + }
>> +
>> + if (!(sim->clk_flag)) {
>> + sim_debug("\n%s enable the clock ret = %d\n", __func__,
>> clk_enable(sim->clk) );
>> + sim->clk_flag = 1;
>> + }
>> +
>> + sim_start(sim);
>> +
>> + return errval;
>> +};
>> +/* Function: sim_fasync
>> + *
>> + * Description: async handler
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static int sim_fasync(int fd, struct file *file, int mode)
>> +{
>> + sim_t *sim = (sim_t *) file->private_data;
>> + pr_debug("%s entering.\n", __func__);
>> + return fasync_helper(fd, file, mode,&sim->fasync);
>> +}
>> +/* Function: sim_release
>> + *
>> + * Description: shut down interface when being closed
>> + *
>> + * Parameters: OS specific
>> + */
>> +
>> +static int sim_release(struct inode *inode, struct file *file)
>> +{
>> + uint32_t reg_data;
>> +
>> + sim_t *sim = (sim_t *) file->private_data;
>> +
>> + sim_debug("%s entering.\n", __func__);
>> + if (sim->clk_flag) {
>> + sim_debug("\n%s disable the clock\n", __func__);
>> + clk_disable(sim->clk);
>> + sim->clk_flag = 0;
>> + }
>> +
>> + /* disable presense detection */
>> + reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
>> + __raw_writel(reg_data | SIM_PORT_DETECT_SDIM, sim->ioaddr + PORT0_DETECT);
>> +
>> + if (sim->present != SIM_PRESENT_REMOVED) {
>> + sim_power_off(sim);
>> + if (sim->fasync)
>> + kill_fasync(&sim->fasync, SIGIO, POLL_IN);
>> + };
>> +
>> + sim_stop(sim);
>> +
>> + sim_fasync(-1, file, 0);
>> +
>> + sim_debug("exit\n");
>> + return 0;
>> +};
>> +
>> +static const struct file_operations sim_fops = {
>> + .owner = THIS_MODULE,
>> + .read = sim_read,
>> + .write = sim_write,
>> + .open = sim_open,
>> + .unlocked_ioctl = sim_ioctl,
>> + .fasync = sim_fasync, // FQ commented
>> + .release = sim_release
>> +};
>> +
>> +// TODO -> Dev name must be dynamic or include all SIM ports
>> +/*
>> +static struct miscdevice sim_dev = {
>> + MISC_DYNAMIC_MINOR,
>> + NULL,
>> + &sim_fops,
>> +};
>> +*/
>> +
>> +/*****************************************************************************\
>> + *
>> *
>> + * Driver init/exit
>> *
>> + *
>> *
>> +\*****************************************************************************/
> Trailing whitespaces here.
>
>> +
>> +static int sim_probe(struct platform_device *pdev)
>> +{
>> + int ret = 0;
>> + struct mxc_sim_platform_data *sim_plat = pdev->dev.platform_data;
>> +
>> + sim_t *sim = kzalloc(sizeof(sim_t), GFP_KERNEL);
>> +
>> + if (sim == 0) {
>> + ret = -ENOMEM;
>> + printk(KERN_ERR "Can't get the MEMORY\n");
>> + return ret;
>> + };
>> +
>> + BUG_ON(pdev == NULL);
>> +
>> + sim->plat_data = sim_plat;
>> + sim->clk_flag = 0;
>> + sim->sim_number = sim->plat_data->sim_number;
>> +
>> + printk(KERN_INFO "Trying initialize port %d...\n", sim->sim_number);
>> +
>> + sim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + if (!sim->res) {
>> + ret = -ENOMEM;
>> + printk(KERN_ERR "Can't get the MEMORY\n");
> Use dev_err here. Also it is useful to print the error value here.
>
>> + goto out;
>> + }
>> +
>> + // request the sim clk and sim_serial_clk
>> + sim_debug("CLK rate:%d\n", sim->plat_data->clk_rate);
>> + sim->clk = clk_get_sys(sim->plat_data->clock_sim, NULL);
>> + if (IS_ERR(sim->clk)) {
>> + ret = PTR_ERR(sim->clk);
>> + printk(KERN_ERR "Get CLK ERROR !\n");
>> + goto out;
>> + }
>> + sim_debug("sim clock:%lu\n", clk_get_rate(sim->clk));
>> +
>> + if (!request_mem_region(sim->res->start,
>> + sim->res->end -
>> + sim->res->start + 1, pdev->name)) {
>> + printk(KERN_ERR "request_mem_region failed\n");
>> + ret = -ENOMEM;
>> + goto out1;
>> + }
>> +
>> + sim->ioaddr = (void *)ioremap(sim->res->start, sim->res->end -
>> + sim->res->start + 1);
> ioremap can fail.
>
>> +
>> + platform_set_drvdata(pdev, sim);
>> + sim_dev.minor = MISC_DYNAMIC_MINOR;
>> + if (sim->sim_number == 0)
>> + sim_dev.name = SIM1_DEV_NAME;
>> + else if (sim->sim_number == 1)
>> + sim_dev.name = SIM2_DEV_NAME;
>> + sim_dev.fops =&sim_fops,
>> + sim_dev.parent =&(pdev->dev);
>> +
>> + misc_register(&sim_dev);
> I suppose this function can fail?
>
>> +
>> + return ret;
>> +
>> +out1:
>> + clk_put(sim->clk);
>> +out:
>> + kfree(sim);
>> + return ret;
>> +}
>> +
>> +static int sim_remove(struct platform_device *pdev)
>> +{
>> + sim_t *sim = platform_get_drvdata(pdev);
>> +
>> + clk_put(sim->clk);
>> +
>> + if (sim->ipb_irq)
>> + free_irq(sim->ipb_irq, sim);
>> + if (sim->dat_irq)
>> + free_irq(sim->dat_irq, sim);
> I see no request_irq anywhere in this patch.
>
>> +
>> + iounmap(sim->ioaddr);
>> +
>> + kfree(sim);
>> + release_mem_region(sim->res->start,
>> + sim->res->end - sim->res->start + 1);
>> +
>> +
>> + misc_deregister(&sim_dev);
>> + return 0;
>> +}
>> +
>> +static struct platform_driver sim_driver = {
>> + .driver = {
>> + .name = DRIVER_NAME,
>> + .owner = THIS_MODULE,
>> + },
>> + .probe = sim_probe,
>> + .remove = sim_remove,
>> + .suspend = NULL,
>> + .resume = NULL,
>> +};
>> +
>> +static int __init sim_drv_init(void)
>> +{
>> + printk(KERN_INFO "IMX : SIM driver\n");
>> +
>> + return platform_driver_register(&sim_driver);
>> +}
>> +
>> +static void __exit sim_drv_exit(void)
>> +{
>> + platform_driver_unregister(&sim_driver);
>> +}
>> +
>> +module_init(sim_drv_init);
>> +module_exit(sim_drv_exit);
>> +
>> +MODULE_AUTHOR("FQ Ingenieria Electronica S.A.");
>> +MODULE_DESCRIPTION("MXC SIM Driver");
>> +MODULE_LICENSE("GPL");
>> --
>> 1.5.4.3
>>
>>
>>
More information about the linux-arm-kernel
mailing list