* [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver @ 2014-05-28 8:57 Satish Patel 2014-05-28 8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel ` (4 more replies) 0 siblings, 5 replies; 19+ messages in thread From: Satish Patel @ 2014-05-28 8:57 UTC (permalink / raw) To: linux-arm-kernel Changes since v2: * RFC comments are fixed for all * ti-usim: ** synchronous card support is added ** Timeout added for ATR ** BWT configuration ** softreset of IP at initialization added ** PM suspend/resume support added * sc_phy : sync card support is added * ARM: dts: AM43xx: fck clock entry is added to usim v1 cover letter link# https://lkml.org/lkml/2014/1/6/250 v2 cover letter link# https://lkml.org/lkml/2014/1/19/168 Satish Patel (5): sc_phy:SmartCard(SC) PHY interface to SC controller misc: tda8026: Add NXP TDA8026 PHY driver char: ti-usim: Add driver for USIM module on AM43xx ARM: dts: AM43xx: DT entries added for ti-usim ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy Documentation/devicetree/bindings/misc/tda8026.txt | 19 + .../devicetree/bindings/ti-usim/ti-usim.txt | 32 + Documentation/sc_phy.txt | 171 ++ arch/arm/boot/dts/am4372.dtsi | 12 + arch/arm/boot/dts/am43x-epos-evm.dts | 31 + drivers/char/Kconfig | 7 + drivers/char/Makefile | 1 + drivers/char/ti-usim-hw.h | 864 ++++++++ drivers/char/ti-usim.c | 2213 ++++++++++++++++++++ drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/tda8026.c | 1258 +++++++++++ include/linux/sc_phy.h | 136 ++ include/linux/ti-usim.h | 111 + 14 files changed, 4863 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt create mode 100644 Documentation/devicetree/bindings/ti-usim/ti-usim.txt create mode 100644 Documentation/sc_phy.txt create mode 100644 drivers/char/ti-usim-hw.h create mode 100644 drivers/char/ti-usim.c create mode 100644 drivers/misc/tda8026.c create mode 100644 include/linux/sc_phy.h create mode 100644 include/linux/ti-usim.h -- 1.7.9.5 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-28 8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel @ 2014-05-28 8:57 ` Satish Patel 2014-05-28 18:44 ` Greg KH 2014-05-28 18:53 ` Greg KH 2014-05-28 8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel ` (3 subsequent siblings) 4 siblings, 2 replies; 19+ messages in thread From: Satish Patel @ 2014-05-28 8:57 UTC (permalink / raw) To: linux-arm-kernel SmartCard controller uses this interface to communicate with SmartCard via PHY Some SmartCard PHY has multiple slots for cards. This inerface also enables controller to communicate with one or more SmartCard connected over phy. interface structure includes following APIs - set/get config - activate/deactivate smart card - warm reset - register_notify (for card insert/remove/overheat) - unregister_notify Signed-off-by: Satish Patel <satish.patel@ti.com> --- Documentation/sc_phy.txt | 171 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/sc_phy.h | 136 ++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 Documentation/sc_phy.txt create mode 100644 include/linux/sc_phy.h diff --git a/Documentation/sc_phy.txt b/Documentation/sc_phy.txt new file mode 100644 index 0000000..d610e26 --- /dev/null +++ b/Documentation/sc_phy.txt @@ -0,0 +1,171 @@ + SmartCard PHY Interface + Satish Patel <satish.patel@ti.com> + +This document explains the SmartCard interface between SmartCard +controller and SmartCard phy. Document also describes how-to-use. + +1. Why SmartCard PHY Interface? + +The use of smartcard is increasing in embedded industry. As smartcard +not only prevent duplication but also, brings key based authentication +flow into picture. + +SmartCard standards like EMV(EuroPay-Mastercard-Visa) are becoming +mandatory for payment terminals. + +Till date, most of the SmartCard readers are based on USB serial +interface. Which drives its logic within firmware lies on device. +Few are based on FPGA solutions. But now SoCs are coming up with +inbuilt smartcard controller. e.g. TI-AM43x + +Role of SmartCard controller and SmartCard phy: + +Smartcard Phy: +Forms electrical interface between controller and SmartCard. Phy +enables access to more than one smartcard and in addition it provides +fast deactivation logic when card gets removed from the slot. It can +also generate the signals like card insert/remove/overheat etc. + +Smartcard Controller: +In built mechanism to meet EMV L1 specification (e.g. T=0, T=1 +protocol timings, ATR timeout etc..) for SmartCard transaction. In +addition to this, it has FIFO to store tx/rx bytes, internal state +machine for ATR, Tx/Rx, Synchronous/Asynchronous mode, timing +counters etc.. + +Controller can also have direct interface through which SmartCard +can be connected without phy. + +Below is the brief of SmartCard block diagram from user to h/w +layer. + + + ----------- + |PC/SC App| + ----------- + ----------- ----------- + |PC/SC F/W| | Visa APP| + ----------- ----------- + ----------- ------------ ------------ + |IFD Hand.| | EMV L1/L2| | Test App | + ----------- ------------ ------------ +User Space +-------------------------------------------------------------------- + + ----------------------------------------- + | SmartCard Controller Driver | + ----------------------------------------- + | | + | | + ------------- | + | Phy Driver | | + ------------- | + | | +Kernel Space | | +-------------------------------------------------------------------- + | | + --------- ---------------- + | PHY | |Controller IP | + --------- ---------------- + | | +-------------------------------------------------------------------- + | | + _______________________________________ + | | | + VISA card Master Card Custom Card + + +At present in Linux there is no public interface exist which acts as +bridge between controller and phy. Mostly vendors uses proprietary +solution in such cases. + +2. Introduction to SmartCard PHY interface + +SmartCard PHY interface that exposes phy's capabilities to the smart +card controller. SmartCard controller uses this interface to +communicate with SmartCard via phy. + +Such capabilities are: +1) Some SmartCard phy (e.g. TDA8026-NxP) has multiple slots for smart +cards. This interface enables controller to communicate with specific +SmartCard inserted to the specific phy's slot. + +2) Warm reset to SmartCard inserted to phy slot. + +3) Bit banging of SmartCard pins to support vedor specific memory +cards. Mostly when it comes to sychorous SmartCard + +4) Notification of card insert/remove/overheat etc. + + +3. How to use + +SmartCard PHY: +The SmartCard PHY driver, who wants to be interfaced with SmartCard +controller require to follow below step + +- include "sc_phy.h" + +- use "sc_phy" structure as driver(client) data. PHY driver can use +'void *pdata' of "sc_phy" to hold its private data(if any) + +- implement following capabilities (whichever is applicable) + set_config + get_config + activate_card + deactivate_card + warm_reset + register_notify + unregister_notify +e.g. +phyxx_init() +{ + + struct sc_phy *sc_phy; + struct phyxx *pdata; + + ... + ... + sc_phy->pdata = pdata; + sc_phy->set_config = phyxx_set_config; + sc_phy->get_config = phyxx_get_config; + sc_phy->activate_card = phyxx_activate_card; +} + +Device Tree Binding: +Refer following reference to bind SmartCard PHY with SmartCard +controller. + + /* SmartCard PHY node */ + &i2c0 { + clock-frequency = <10000000>; + phyxx: phyxx at yy { + compatible = "xyz,abc"; + reg = <0xyy>; + }; + }; + + /* SmartCard Controller node*/ + &usim0 { + .... + phy = <&phyxx>; + phy-slots = <1>; + }; + +SmartCard Controller: +- Access PHY interface using DT. +Refer below example code + + phy_i2c = of_find_i2c_device_by_node(phy_node); + if (phy_i2c == NULL) { + ret = -EINVAL; + } + + /* get phy interface */ + sc_phy = (struct sc_phy *)i2c_get_clientdata(phy_i2c); + + /* register notifier */ + sc_phy->register_notify(sc_phy, ¬ifier_cb, (void *)data); + + +- Controller can use then after all defined SmartCard PHY interface diff --git a/include/linux/sc_phy.h b/include/linux/sc_phy.h new file mode 100644 index 0000000..9aed530 --- /dev/null +++ b/include/linux/sc_phy.h @@ -0,0 +1,136 @@ +/* + * sc_phy.h - Header file for Smart Card PHY operations. + * This is a smart card phy's interface to smart card controller. + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SC_PHY_H__ +#define __SC_PHY_H__ + +#include <linux/notifier.h> + +/* defines used in notify action + * action will be composed of two part + * | 0x0000 | <slot> - 2 bytes| <action>- 2 bytes | + */ +#define SC_PHY_NOTIFICATION_ACTION_MASK (0x000000ffU) +#define SC_PHY_NOTIFICATION_ACTION_SHIFT (0) + +#define SC_PHY_NOTIFICATION_SLOT_MASK (0x0000ff00U) +#define SC_PHY_NOTIFICATION_SLOT_SHIFT (8) +/* + * smart card supply voltage levels + */ +enum sc_supply_voltage { + SC_PHY_5V = 0, + SC_PHY_3V, + SC_PHY_1_8V +}; + +/* + * smarcard type - async or sync + */ +enum sc_phy_card_mode { + SC_PHY_ASYNC = 0, + SC_PHY_SYNC, + SC_PHY_SYNC_TYPE1, + SC_PHY_SYNC_TYPE2, +}; + +/* + * phy operational modes + */ +enum sc_phy_mode { + SC_PHY_ACTIVE = 0x11, + SC_PHY_CLOCKSTOP, + SC_PHY_STANDBY, + SC_PHY_SHUTDOWN, + SC_PHY_REMOVED, +}; + +/* + * smartcard actions. more actions will be as they gets introduced in upcoming + * smart card phys. + */ +enum sc_phy_card_action { + SC_PHY_CARD_INSERTED = 0x1, + SC_PHY_CARD_REMOVED = 0x2, + SC_PHY_CARD_OVERHEAT = 0x4, + SC_PHY_CARD_ATR_TIMEOUT = 0x8, + SC_PHY_CARD_SYNC_ACT_COMPLETE = 0x10, +}; + +/* + * configuration parameters of smart card phy + */ +enum sc_phy_config { + SC_PHY_VERSION = 0, + SC_PHY_CARD_SUPPLY_VOLTAGE, + SC_PHY_CARD_PRESENCE, + SC_PHY_ATR_MUTE_TIME, + SC_PHY_ATR_EARLY_TIME, + SC_PHY_CARD_MODE, /* sync or async mode */ + SC_PHY_IO, /* disable or enable i/o line connected to phy */ + SC_PHY_CLKDIV, /* clock division for the clock supplied to phy */ + SC_PHY_MODE, + SC_PHY_PIN_CLK, + SC_PHY_PIN_RST, + SC_PHY_PIN_C4, + SC_PHY_PIN_C8 +}; +/** + * struct sc_phy - The basic smart card phy structure + * + * @dev: phy device + * @pdata: pointer to phy's private data structure + * @set_config: called to set phy's configuration + * @get_config: called to get phy's configuration + * @activate_card: perform smart card activation + * @deactivate_card: perform smart card de-activation + * @warm_reset: execute smart card warm reset sequence + * @register_card_activity_cb: register call back to phy device. + * This call back will be called on card insert or remove event + * + * smart card controller uses this interface to communicate with + * smart card via phy.Some smart card phy has multiple slots for + * cards. This inerface also enables controller to communicate with + * one or more smart card connected over phy. + */ +struct sc_phy { + /* phy's device pointer */ + struct device *dev; + + /* phy's private data */ + void *pdata; + + /* notify data, passed by interface user as a part of + * register_notify API. Data should be passed back when + * notification raised to the interface user + */ + void *notify_data; + + int (*set_config)(struct sc_phy *phy, u8 slot, + enum sc_phy_config attr, int value); + int (*get_config)(struct sc_phy *phy, u8 slot, enum + sc_phy_config attr); + int (*activate_card)(struct sc_phy *phy, u8 slot); + int (*deactivate_card)(struct sc_phy *phy, u8 slot); + int (*get_syncatr)(struct sc_phy *phy, u8 slot, u8 len, char *atr); + int (*warm_reset)(struct sc_phy *phy, u8 slot); + int (*register_notify)(struct sc_phy *phy, + struct notifier_block *nb, void *notify_data); + int (*unregister_notify)(struct sc_phy *phy, + struct notifier_block *nb); +}; + +#endif /* __SC_PHY_H__ */ -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-28 8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel @ 2014-05-28 18:44 ` Greg KH 2014-05-29 8:56 ` Satish Patel 2014-05-28 18:53 ` Greg KH 1 sibling, 1 reply; 19+ messages in thread From: Greg KH @ 2014-05-28 18:44 UTC (permalink / raw) To: linux-arm-kernel On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: > +/** > + * struct sc_phy - The basic smart card phy structure > + * > + * @dev: phy device > + * @pdata: pointer to phy's private data structure > + * @set_config: called to set phy's configuration > + * @get_config: called to get phy's configuration > + * @activate_card: perform smart card activation > + * @deactivate_card: perform smart card de-activation > + * @warm_reset: execute smart card warm reset sequence > + * @register_card_activity_cb: register call back to phy device. > + * This call back will be called on card insert or remove event > + * > + * smart card controller uses this interface to communicate with > + * smart card via phy.Some smart card phy has multiple slots for > + * cards. This inerface also enables controller to communicate with > + * one or more smart card connected over phy. > + */ > +struct sc_phy { > + /* phy's device pointer */ > + struct device *dev; So this is the "parent", right? Why not embed a struct device into this structure as well, further streaching out the device tree. > + > + /* phy's private data */ > + void *pdata; If you do the above, then this pointer is not needed. > + > + /* notify data, passed by interface user as a part of > + * register_notify API. Data should be passed back when > + * notification raised to the interface user > + */ > + void *notify_data; What makes this different from the pdata? > + > + int (*set_config)(struct sc_phy *phy, u8 slot, > + enum sc_phy_config attr, int value); > + int (*get_config)(struct sc_phy *phy, u8 slot, enum > + sc_phy_config attr); > + int (*activate_card)(struct sc_phy *phy, u8 slot); > + int (*deactivate_card)(struct sc_phy *phy, u8 slot); > + int (*get_syncatr)(struct sc_phy *phy, u8 slot, u8 len, char *atr); > + int (*warm_reset)(struct sc_phy *phy, u8 slot); > + int (*register_notify)(struct sc_phy *phy, > + struct notifier_block *nb, void *notify_data); > + int (*unregister_notify)(struct sc_phy *phy, > + struct notifier_block *nb); > +}; > + > +#endif /* __SC_PHY_H__ */ > -- > 1.7.9.5 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-28 18:44 ` Greg KH @ 2014-05-29 8:56 ` Satish Patel 2014-05-29 15:51 ` Greg KH 0 siblings, 1 reply; 19+ messages in thread From: Satish Patel @ 2014-05-29 8:56 UTC (permalink / raw) To: linux-arm-kernel On 5/29/2014 12:14 AM, Greg KH wrote: > On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: >> +/** >> + * struct sc_phy - The basic smart card phy structure >> + * >> + * @dev: phy device >> + * @pdata: pointer to phy's private data structure >> + * @set_config: called to set phy's configuration >> + * @get_config: called to get phy's configuration >> + * @activate_card: perform smart card activation >> + * @deactivate_card: perform smart card de-activation >> + * @warm_reset: execute smart card warm reset sequence >> + * @register_card_activity_cb: register call back to phy device. >> + * This call back will be called on card insert or remove event >> + * >> + * smart card controller uses this interface to communicate with >> + * smart card via phy.Some smart card phy has multiple slots for >> + * cards. This inerface also enables controller to communicate with >> + * one or more smart card connected over phy. >> + */ >> +struct sc_phy { >> + /* phy's device pointer */ >> + struct device *dev; > > So this is the "parent", right? Why not embed a struct device into this > structure as well, further streaching out the device tree. > Do you mean to use "dev->p" for pdata ? I have kept it outside, to give easeness/pragmatic focal for new phy driver development. Driver can make this pointer null and use above pointer. >> + >> + /* phy's private data */ >> + void *pdata; > > If you do the above, then this pointer is not needed. > > >> + >> + /* notify data, passed by interface user as a part of >> + * register_notify API. Data should be passed back when >> + * notification raised to the interface user >> + */ >> + void *notify_data; > > What makes this different from the pdata? pdata is phy's private data, while notify_data is something phy will send to smart card controller on some event, like card remove/insert/timeout etc.. > > >> + >> + int (*set_config)(struct sc_phy *phy, u8 slot, >> + enum sc_phy_config attr, int value); >> + int (*get_config)(struct sc_phy *phy, u8 slot, enum >> + sc_phy_config attr); >> + int (*activate_card)(struct sc_phy *phy, u8 slot); >> + int (*deactivate_card)(struct sc_phy *phy, u8 slot); >> + int (*get_syncatr)(struct sc_phy *phy, u8 slot, u8 len, char *atr); >> + int (*warm_reset)(struct sc_phy *phy, u8 slot); >> + int (*register_notify)(struct sc_phy *phy, >> + struct notifier_block *nb, void *notify_data); >> + int (*unregister_notify)(struct sc_phy *phy, >> + struct notifier_block *nb); >> +}; >> + >> +#endif /* __SC_PHY_H__ */ >> -- >> 1.7.9.5 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-29 8:56 ` Satish Patel @ 2014-05-29 15:51 ` Greg KH 2014-05-30 5:05 ` Satish Patel 0 siblings, 1 reply; 19+ messages in thread From: Greg KH @ 2014-05-29 15:51 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 29, 2014 at 02:26:55PM +0530, Satish Patel wrote: > > > On 5/29/2014 12:14 AM, Greg KH wrote: > >On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: > >>+/** > >>+ * struct sc_phy - The basic smart card phy structure > >>+ * > >>+ * @dev: phy device > >>+ * @pdata: pointer to phy's private data structure > >>+ * @set_config: called to set phy's configuration > >>+ * @get_config: called to get phy's configuration > >>+ * @activate_card: perform smart card activation > >>+ * @deactivate_card: perform smart card de-activation > >>+ * @warm_reset: execute smart card warm reset sequence > >>+ * @register_card_activity_cb: register call back to phy device. > >>+ * This call back will be called on card insert or remove event > >>+ * > >>+ * smart card controller uses this interface to communicate with > >>+ * smart card via phy.Some smart card phy has multiple slots for > >>+ * cards. This inerface also enables controller to communicate with > >>+ * one or more smart card connected over phy. > >>+ */ > >>+struct sc_phy { > >>+ /* phy's device pointer */ > >>+ struct device *dev; > > > >So this is the "parent", right? Why not embed a struct device into this > >structure as well, further streaching out the device tree. > > > Do you mean to use "dev->p" for pdata ? No, use the device itself. > I have kept it outside, to give easeness/pragmatic focal for new phy driver > development. Driver can make this pointer null and use above pointer. Ick, no, that's not how the driver model works. Each device in the system needs a struct device, don't try to "chain" off of an existing device like this. Make it a "real" one. > >>+ > >>+ /* phy's private data */ > >>+ void *pdata; > > > >If you do the above, then this pointer is not needed. > > > > > >>+ > >>+ /* notify data, passed by interface user as a part of > >>+ * register_notify API. Data should be passed back when > >>+ * notification raised to the interface user > >>+ */ > >>+ void *notify_data; > > > >What makes this different from the pdata? > pdata is phy's private data, while notify_data is something phy will send to > smart card controller on some event, like card remove/insert/timeout etc.. That doesn't make much sense to me, why not just put that in the notify function callback itself? Please either use the existing phy layer of the kernel, or make a "real" subsystem here, don't try to put a tiny shim on top of an existing struct device for this driver, that's not how subsystems in Linux are done. thanks, greg k-h ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-29 15:51 ` Greg KH @ 2014-05-30 5:05 ` Satish Patel 0 siblings, 0 replies; 19+ messages in thread From: Satish Patel @ 2014-05-30 5:05 UTC (permalink / raw) To: linux-arm-kernel On 5/29/2014 9:21 PM, Greg KH wrote: > On Thu, May 29, 2014 at 02:26:55PM +0530, Satish Patel wrote: >> >> >> On 5/29/2014 12:14 AM, Greg KH wrote: >>> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: >>>> +/** >>>> + * struct sc_phy - The basic smart card phy structure >>>> + * >>>> + * @dev: phy device >>>> + * @pdata: pointer to phy's private data structure >>>> + * @set_config: called to set phy's configuration >>>> + * @get_config: called to get phy's configuration >>>> + * @activate_card: perform smart card activation >>>> + * @deactivate_card: perform smart card de-activation >>>> + * @warm_reset: execute smart card warm reset sequence >>>> + * @register_card_activity_cb: register call back to phy device. >>>> + * This call back will be called on card insert or remove event >>>> + * >>>> + * smart card controller uses this interface to communicate with >>>> + * smart card via phy.Some smart card phy has multiple slots for >>>> + * cards. This inerface also enables controller to communicate with >>>> + * one or more smart card connected over phy. >>>> + */ >>>> +struct sc_phy { >>>> + /* phy's device pointer */ >>>> + struct device *dev; >>> >>> So this is the "parent", right? Why not embed a struct device into this >>> structure as well, further streaching out the device tree. >>> >> Do you mean to use "dev->p" for pdata ? > > No, use the device itself. > >> I have kept it outside, to give easeness/pragmatic focal for new phy driver >> development. Driver can make this pointer null and use above pointer. > > Ick, no, that's not how the driver model works. Each device in the > system needs a struct device, don't try to "chain" off of an existing > device like this. Make it a "real" one. > >>>> + >>>> + /* phy's private data */ >>>> + void *pdata; >>> >>> If you do the above, then this pointer is not needed. >>> >>> >>>> + >>>> + /* notify data, passed by interface user as a part of >>>> + * register_notify API. Data should be passed back when >>>> + * notification raised to the interface user >>>> + */ >>>> + void *notify_data; >>> >>> What makes this different from the pdata? >> pdata is phy's private data, while notify_data is something phy will send to >> smart card controller on some event, like card remove/insert/timeout etc.. > > That doesn't make much sense to me, why not just put that in the notify > function callback itself? > Little correction over here.. Here is brief flow USIM(Smart Card Controller) register notification callback to smarcard phy. usim->phy->register_notify(<phy handle>, <callback fn>, <notify_data>); notify_data : pass back when callback function will be called by PHY Smartcard PHY -> USIM blocking_notifier_call_chain(<notifier>, action, <notify_data>); action : card insert/remove/overheat etc.. notify data: USIM data passing back (supplied at the time of cb registration) > Please either use the existing phy layer of the kernel, or make a "real" > subsystem here, don't try to put a tiny shim on top of an existing > struct device for this driver, that's not how subsystems in Linux are > done. Why I am not using exiting PHY framework ? We will be more than happy to adapt generic phy if it includes/add support for smart card requirements like 1) Some smart card phy (TDA8026-NxP) has multiple slots for smart cards. This interface enables controller to communicate with specific smart card inserted to the specific phy's slot. 2) Warm reset to smart card inserted to phy slot. 3) Bit banging of smart card pins to support vendor specific memory cards. 4) Notification of card insert/remove/overheat etc. 5) synchronous and asynchronous modes for smart card transaction > > thanks, > > greg k-h > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-28 8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel 2014-05-28 18:44 ` Greg KH @ 2014-05-28 18:53 ` Greg KH 2014-05-29 8:34 ` Satish Patel 1 sibling, 1 reply; 19+ messages in thread From: Greg KH @ 2014-05-28 18:53 UTC (permalink / raw) To: linux-arm-kernel On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: > SmartCard controller uses this interface to communicate with > SmartCard via PHY > > Some SmartCard PHY has multiple slots for cards. > This inerface also enables controller to communicate > with one or more SmartCard connected over phy. > > interface structure includes following APIs > - set/get config > - activate/deactivate smart card > - warm reset > - register_notify (for card insert/remove/overheat) > - unregister_notify > > Signed-off-by: Satish Patel <satish.patel@ti.com> > --- > Documentation/sc_phy.txt | 171 ++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/sc_phy.h | 136 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 307 insertions(+) > create mode 100644 Documentation/sc_phy.txt > create mode 100644 include/linux/sc_phy.h These are .h files, but where is the "api" functions that use these structures defined at? confused, greg k-h ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-28 18:53 ` Greg KH @ 2014-05-29 8:34 ` Satish Patel 2014-05-29 13:47 ` Rob Herring 0 siblings, 1 reply; 19+ messages in thread From: Satish Patel @ 2014-05-29 8:34 UTC (permalink / raw) To: linux-arm-kernel On 5/29/2014 12:23 AM, Greg KH wrote: > On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: >> SmartCard controller uses this interface to communicate with >> SmartCard via PHY >> >> Some SmartCard PHY has multiple slots for cards. >> This inerface also enables controller to communicate >> with one or more SmartCard connected over phy. >> >> interface structure includes following APIs >> - set/get config >> - activate/deactivate smart card >> - warm reset >> - register_notify (for card insert/remove/overheat) >> - unregister_notify >> >> Signed-off-by: Satish Patel <satish.patel@ti.com> >> --- >> Documentation/sc_phy.txt | 171 ++++++++++++++++++++++++++++++++++++++++++++++ >> include/linux/sc_phy.h | 136 ++++++++++++++++++++++++++++++++++++ >> 2 files changed, 307 insertions(+) >> create mode 100644 Documentation/sc_phy.txt >> create mode 100644 include/linux/sc_phy.h > > These are .h files, but where is the "api" functions that use > these structures defined at? > This is like template/wrappers, smart card phy driver will write API functions. And smartcard controller will call these functions. With proposed approach, smartcard controller can communicate with any smart card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY will gets connected with each other. Refer diagram given @Documentation/sc_phy.txt. > confused, > > greg k-h > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-29 8:34 ` Satish Patel @ 2014-05-29 13:47 ` Rob Herring 2014-05-29 15:52 ` Greg KH 2014-05-30 3:51 ` Satish Patel 0 siblings, 2 replies; 19+ messages in thread From: Rob Herring @ 2014-05-29 13:47 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 29, 2014 at 3:34 AM, Satish Patel <satish.patel@ti.com> wrote: > > > On 5/29/2014 12:23 AM, Greg KH wrote: >> >> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: >>> >>> SmartCard controller uses this interface to communicate with >>> SmartCard via PHY >>> >>> Some SmartCard PHY has multiple slots for cards. >>> This inerface also enables controller to communicate >>> with one or more SmartCard connected over phy. >>> >>> interface structure includes following APIs >>> - set/get config >>> - activate/deactivate smart card >>> - warm reset >>> - register_notify (for card insert/remove/overheat) >>> - unregister_notify >>> >>> Signed-off-by: Satish Patel <satish.patel@ti.com> >>> --- >>> Documentation/sc_phy.txt | 171 >>> ++++++++++++++++++++++++++++++++++++++++++++++ >>> include/linux/sc_phy.h | 136 ++++++++++++++++++++++++++++++++++++ >>> 2 files changed, 307 insertions(+) >>> create mode 100644 Documentation/sc_phy.txt >>> create mode 100644 include/linux/sc_phy.h >> >> >> These are .h files, but where is the "api" functions that use >> these structures defined at? >> > This is like template/wrappers, smart card phy driver will write API > functions. And smartcard controller will call these functions. > With proposed approach, smartcard controller can communicate with any smart > card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY > will gets connected with each other. > Refer diagram given @Documentation/sc_phy.txt. > > >> confused, I believe the api Greg is wondering about is the notifier which as I commented is not a good design. There is now a phy subsystem. I don't know if it has what you need, but you should look at it to determine if it will work or could be extended to work. Rob ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-29 13:47 ` Rob Herring @ 2014-05-29 15:52 ` Greg KH 2014-05-30 3:51 ` Satish Patel 1 sibling, 0 replies; 19+ messages in thread From: Greg KH @ 2014-05-29 15:52 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 29, 2014 at 08:47:31AM -0500, Rob Herring wrote: > On Thu, May 29, 2014 at 3:34 AM, Satish Patel <satish.patel@ti.com> wrote: > > > > > > On 5/29/2014 12:23 AM, Greg KH wrote: > >> > >> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: > >>> > >>> SmartCard controller uses this interface to communicate with > >>> SmartCard via PHY > >>> > >>> Some SmartCard PHY has multiple slots for cards. > >>> This inerface also enables controller to communicate > >>> with one or more SmartCard connected over phy. > >>> > >>> interface structure includes following APIs > >>> - set/get config > >>> - activate/deactivate smart card > >>> - warm reset > >>> - register_notify (for card insert/remove/overheat) > >>> - unregister_notify > >>> > >>> Signed-off-by: Satish Patel <satish.patel@ti.com> > >>> --- > >>> Documentation/sc_phy.txt | 171 > >>> ++++++++++++++++++++++++++++++++++++++++++++++ > >>> include/linux/sc_phy.h | 136 ++++++++++++++++++++++++++++++++++++ > >>> 2 files changed, 307 insertions(+) > >>> create mode 100644 Documentation/sc_phy.txt > >>> create mode 100644 include/linux/sc_phy.h > >> > >> > >> These are .h files, but where is the "api" functions that use > >> these structures defined at? > >> > > This is like template/wrappers, smart card phy driver will write API > > functions. And smartcard controller will call these functions. > > With proposed approach, smartcard controller can communicate with any smart > > card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY > > will gets connected with each other. > > Refer diagram given @Documentation/sc_phy.txt. > > > > > >> confused, > > I believe the api Greg is wondering about is the notifier which as I > commented is not a good design. That, and the fact that if this really is an "api", there are no .c files for it like a "normal" api is in the kernel. > There is now a phy subsystem. I don't know if it has what you need, > but you should look at it to determine if it will work or could be > extended to work. I agree. Satish, what's wrong with our existing phy layer? greg k-h ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller 2014-05-29 13:47 ` Rob Herring 2014-05-29 15:52 ` Greg KH @ 2014-05-30 3:51 ` Satish Patel 1 sibling, 0 replies; 19+ messages in thread From: Satish Patel @ 2014-05-30 3:51 UTC (permalink / raw) To: linux-arm-kernel On 5/29/2014 7:17 PM, Rob Herring wrote: > On Thu, May 29, 2014 at 3:34 AM, Satish Patel <satish.patel@ti.com> wrote: >> >> >> On 5/29/2014 12:23 AM, Greg KH wrote: >>> >>> On Wed, May 28, 2014 at 02:27:13PM +0530, Satish Patel wrote: >>>> >>>> SmartCard controller uses this interface to communicate with >>>> SmartCard via PHY >>>> >>>> Some SmartCard PHY has multiple slots for cards. >>>> This inerface also enables controller to communicate >>>> with one or more SmartCard connected over phy. >>>> >>>> interface structure includes following APIs >>>> - set/get config >>>> - activate/deactivate smart card >>>> - warm reset >>>> - register_notify (for card insert/remove/overheat) >>>> - unregister_notify >>>> >>>> Signed-off-by: Satish Patel <satish.patel@ti.com> >>>> --- >>>> Documentation/sc_phy.txt | 171 >>>> ++++++++++++++++++++++++++++++++++++++++++++++ >>>> include/linux/sc_phy.h | 136 ++++++++++++++++++++++++++++++++++++ >>>> 2 files changed, 307 insertions(+) >>>> create mode 100644 Documentation/sc_phy.txt >>>> create mode 100644 include/linux/sc_phy.h >>> >>> >>> These are .h files, but where is the "api" functions that use >>> these structures defined at? >>> >> This is like template/wrappers, smart card phy driver will write API >> functions. And smartcard controller will call these functions. >> With proposed approach, smartcard controller can communicate with any smart >> card phy (TI/NxP) without change in code. Using DT entry smartcard and PHY >> will gets connected with each other. >> Refer diagram given @Documentation/sc_phy.txt. >> >> >>> confused, > > I believe the api Greg is wondering about is the notifier which as I > commented is not a good design. > > There is now a phy subsystem. I don't know if it has what you need, > but you should look at it to determine if it will work or could be > extended to work. > I have given my comments on notifier, it is required to notify real time events like card insert/remove to the smart card controller. As this interrupts tied to phy (in case phy is present) not with controller. Existing phy subsystem does not support generic operations for the phy. If at all it adds supports for these, in future I am ok to get align with it. > Rob > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver 2014-05-28 8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel 2014-05-28 8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel @ 2014-05-28 8:57 ` Satish Patel 2014-05-28 18:44 ` Greg KH 2014-05-28 8:57 ` [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim Satish Patel ` (2 subsequent siblings) 4 siblings, 1 reply; 19+ messages in thread From: Satish Patel @ 2014-05-28 8:57 UTC (permalink / raw) To: linux-arm-kernel TDA8026 is a SmartCard PHY from NXP. The PHY interfaces with the main processor over the I2C interface and acts as a slave device. The driver also exposes the phy interface (defined at include/linux/sc_phy.h) for SmartCard controller. Controller uses this interface to communicate with smart card inserted to the phy's slot. Note: gpio irq is not validated as I do not have device with that. I have validated interrupt with dedicated interrupt line on my device. Signed-off-by: Satish Patel <satish.patel@ti.com> --- Documentation/devicetree/bindings/misc/tda8026.txt | 19 + drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/tda8026.c | 1258 ++++++++++++++++++++ 4 files changed, 1285 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt create mode 100644 drivers/misc/tda8026.c diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt new file mode 100644 index 0000000..f115c9c --- /dev/null +++ b/Documentation/devicetree/bindings/misc/tda8026.txt @@ -0,0 +1,19 @@ +TDA8026 smart card slot interface + +This is an i2c based smart card interface device forming the electrical +interface between a microcontroller and smart cards. This device supports +asynchronous cards (micro controller-based IC cards) as well as synchronous +cards (mainly memory cards) + +Required properties: +- compatible: "nxp,tda8026" +- shutdown-gpio = GPIO pin mapping for SDWNN pin +- reg = i2c interface address + + +Example: +tda8026: tda8026 at 48 { + compatible = "nxp,tda8026"; + reg = <0x48>; + shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */ + }; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8baff0e..80b21d7 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -515,6 +515,13 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. +config NXP_TDA8026_PHY + tristate "NXP PHY Driver for Smart Card PHY" + depends on I2C=y + help + If you say yes here you get support for the TDA8026 Smart card PHY + with I2C interface. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7eb4b69..f262c0b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o obj-y += mic/ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ +obj-$(CONFIG_NXP_TDA8026_PHY) += tda8026.o diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c new file mode 100644 index 0000000..38df33e --- /dev/null +++ b/drivers/misc/tda8026.c @@ -0,0 +1,1258 @@ +/* + * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY + * + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/mfd/core.h> +#include <linux/notifier.h> +#include <linux/sc_phy.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> +#include <linux/delay.h> + +#define TDA8026_MAX_SLOTS (5) +#define TDA8026_NUM_SAM_SLOTS (4) +#define TDA8026_USERCARD_SLOT (1) + +#define TDA8026_CSB_ADDR (0x24) +#define TDA8026_REG0_ADDR (0x20) +#define TDA8026_REG1_ADDR (0x21) +#define TDA8026_SLEWRATE_ADDR (0x20) +#define TDA8026_PRODVER_ADDR (0x20) +#define TDA8026_INTSTAT_ADDR (0x21) + +#define TDA8026_PHY_PRODUCT_VERSION (0xC2) + +/* CSB register values */ +#define TDA8026_CSB_PV_INTSTAT_VAL (0x0) +#define TDA8026_CSB_SLEWRATE_VAL (0x6) + +/* Slot REG0 read mode bit fields */ +#define TDA8026_REG0_ACTIVE_MASK (0x80) +#define TDA8026_REG0_EARLY_MASK (0x40) +#define TDA8026_REG0_MUTE_MASK (0x20) +#define TDA8026_REG0_PROT_MASK (0x10) +#define TDA8026_REG0_SUPL_MASK (0x08) +#define TDA8026_REG0_CLKSW_MASK (0x04) +#define TDA8026_REG0_PREL_MASK (0x02) +#define TDA8026_REG0_PRES_MASK (0x01) + +/* Slot REG0 write mode bit fields */ +#define TDA8026_REG0_VCC1V8_MASK (0x80) +#define TDA8026_REG0_IOEN_MASK (0x40) + +#define TDA8026_REG0_REG10_MASK (0x30) +#define TDA8026_REG0_REG10_SHIFT (4) +#define TDA8026_REG0_REG10_CFG_VAL (0x0) +#define TDA8026_REG0_REG10_D_VAL (0x1) +#define TDA8026_REG0_REG10_CMSB_VAL (0x2) +#define TDA8026_REG0_REG10_CLSB_VAL (0x3) + +#define TDA8026_REG0_PDWN_MASK (0x08) +#define TDA8026_REG0_5V3VN_MASK (0x04) +#define TDA8026_REG0_WARM_RESET_MASK (0x02) +#define TDA8026_REG0_START_MASK (0x01) + +/* Slot REG1 CFG bit fields REG[1:0] = 00b */ +#define TDA8026_REG1CFG_CFGP2_MASK (0x80) +#define TDA8026_REG1CFG_RSTIN_MASK (0x40) +#define TDA8026_REG1CFG_C8_MASK (0x20) +#define TDA8026_REG1CFG_C4_MASK (0x10) +#define TDA8026_REG1CFG_CLKPD_MASK (0x0C) +#define TDA8026_REG1CFG_CLKPD_SHIFT (2) +#define TDA8026_REG1CFG_CLKDIV_MASK (0x03) +#define TDA8026_REG1CFG_CLKDIV_SHIFT (0) + +/* Slew rate register bit fields */ +#define TDA8026_SR_CLKSR_SLOT0_MASK 0x0C +#define TDA8026_SR_CLKSR_SLOT0_SHIFT 0x2 +#define TDA8026_SR_IOSR_SLOT0_MASK 0x3 +#define TDA8026_SR_IOSR_SLOT0_SHIFT 0x0 + +#define TDA8026_SR_CLKSR_SLOT2TO5_MASK 0xC0 +#define TDA8026_SR_CLKSR_SLOT2TO5_SHIFT 0x6 +#define TDA8026_SR_IOSR_SLOT2TO5_MASK 0x30 +#define TDA8026_SR_IOSR_SLOT2TO5_SHIFT 0x4 + +#define TDA8026_MIN_EARLY_CYCLE (200) + +struct tda8026 { + /* device pointer */ + struct device *dev; + + /* For device IO interfaces: I2C or SPI */ + void *control_data; + /* Store a shadow of Slot Register 0 as it cannot be read */ + u8 reg0[TDA8026_MAX_SLOTS]; + int irq; + int notify; + int shutdown_gpio; + int enable; +}; + +static BLOCKING_NOTIFIER_HEAD(tda8026_notifier_list); + +static int tda8026_i2c_read(struct tda8026 *tda8026, u8 reg, + int bytes, u8 *dest) +{ + struct i2c_client *i2c = tda8026->control_data; + struct i2c_msg xfer; + int ret; + + /* We need to read from the slave address itself, as there + * is no separate register to be accessed in TDA8026 + */ + + xfer.addr = reg; + xfer.flags = I2C_M_RD; + xfer.len = bytes; + xfer.buf = dest; + + ret = i2c_transfer(i2c->adapter, &xfer, 1); + if (ret < 0) + dev_err(tda8026->dev, "Read [0x%x] Error %d\n", reg, ret); + + return ret; +} + +static int tda8026_i2c_write(struct tda8026 *tda8026, u8 reg, + int bytes, u8 *src) +{ + struct i2c_client *i2c = tda8026->control_data; + struct i2c_msg xfer; + int ret; + + /* We have to write to the slave address itself, as + * there is no separate register to be accessed in TDA8026 + */ + xfer.addr = reg; + xfer.flags = 0; + xfer.len = bytes; + xfer.buf = src; + + ret = i2c_transfer(i2c->adapter, &xfer, 1); + if (ret < 0) + dev_err(tda8026->dev, "Write [0x%x] Error %d\n", reg, ret); + + return ret; +} + +/* put the phy in shutdown mode, which in turn deactivate + * all the cards in the slot and card pins are forced to 0V + */ +static inline void tda8026_disable(struct tda8026 *tda8026) +{ + dev_dbg(tda8026->dev, "tda8026_disable!!!!"); + tda8026->enable = 0; + if (gpio_is_valid(tda8026->shutdown_gpio)) + gpio_set_value(tda8026->shutdown_gpio, 0); +} + +/* exit from shutdown mode */ +static inline void tda8026_enable(struct tda8026 *tda8026) +{ + dev_dbg(tda8026->dev, "tda8026_enable!!!!"); + tda8026->enable = 1; + if (gpio_is_valid(tda8026->shutdown_gpio)) + gpio_set_value(tda8026->shutdown_gpio, 1); + /* Added dealy to stabilized phy state after pulling shutdown line */ + mdelay(100); +} + +/* + * Select the card slot to communicate with the card + * Note that card slots are numbered from 0 in software. + * However TDA8026 PHY numbers the slot starting 1. + */ +static inline int tda8026_select_slot(struct tda8026 *tda8026, u8 slot) +{ + int ret = 0; + + /* In SW slot starts from 0, in TDA8026 it starts from 1 */ + slot = slot + 1; + ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &slot); + + return ret; +} + +static int tda8026_clear_interrupts(struct tda8026 *tda8026) +{ + u8 val; + u8 status; + int ret = 0; + + /* Select the Interrupt register bank */ + val = TDA8026_CSB_PV_INTSTAT_VAL; + tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val); + + /* Read the interrupt status which will tell us the slot */ + ret = tda8026_i2c_read(tda8026, TDA8026_INTSTAT_ADDR, 1, &status); + if (ret < 0) + return ret; + + for (val = 1; val > TDA8026_MAX_SLOTS; val++) { + /* Program the slot number to the CSB register */ + ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val); + if (ret < 0) + return ret; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG0_ADDR, 1, &status); + if (ret < 0) + return ret; + } + return ret; +} +/* + * TDA8026 PHY IRQ handler + */ +static irqreturn_t tda8026_irq(int irq, void *irq_data) +{ + struct sc_phy *phy_tda8026 = (struct sc_phy *)irq_data; + struct tda8026 *tda8026 = (struct tda8026 *)phy_tda8026->pdata; + u8 slot; + u8 val; + u8 status; + int ret = 0; + int action = 0; + + dev_dbg(tda8026->dev, "tda8026_irq!!"); + + if (tda8026->enable == 0) { + dev_dbg(tda8026->dev, "phy is disable not serving interrputs!!"); + /* when, phy is in shutdown mode, it can detect the card insert + * event. But if phy is not enable (i.e.) there is no consumer + * of phy then just enable phy, clear the interrupt and disable + * again + */ + tda8026_enable(tda8026); + tda8026_clear_interrupts(tda8026); + tda8026_disable(tda8026); + return IRQ_HANDLED; + } + + /* Select the Interrupt register bank */ + val = TDA8026_CSB_PV_INTSTAT_VAL; + tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val); + + /* Read the interrupt status which will tell us the slot */ + ret = tda8026_i2c_read(tda8026, TDA8026_INTSTAT_ADDR, 1, &status); + if (ret < 0) + return IRQ_HANDLED; + + + /* find out for which slot interrupt has occur */ + slot = 0; + while (val == 0 && slot < TDA8026_MAX_SLOTS) { + val = status & (1 << slot); + slot++; + } + + if (slot > TDA8026_MAX_SLOTS) { + dev_err(tda8026->dev, "invalid slot interrput"); + return IRQ_HANDLED; + } + + /* Program the slot number to the CSB register */ + ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &slot); + if (ret < 0) + return IRQ_HANDLED; + + /* Now read the slot reg0 to find out the cause of interrupt + * Note that IRQ is raised only when one of the SUPL, PROT, + * MUTE and EARLY bits are set to logic 1. + */ + ret = tda8026_i2c_read(tda8026, TDA8026_REG0_ADDR, 1, &status); + if (ret < 0) + return IRQ_HANDLED; + + if (slot < 3) { + /* slot 1 and slot 2 can be used for user card, it can raise + * interrupt for card insert and remove.Other slot are for SAM + * modules. They are either always present or alwyas absent + */ + if (status & TDA8026_REG0_PREL_MASK) { + if (status & TDA8026_REG0_PRES_MASK) { + dev_dbg(tda8026->dev, "card is inserted"); + action |= SC_PHY_CARD_INSERTED; + } else { + dev_dbg(tda8026->dev, "card is removed"); + action |= SC_PHY_CARD_REMOVED; + } + } + } + + if (status & (TDA8026_REG0_EARLY_MASK | TDA8026_REG0_MUTE_MASK)) { + dev_dbg(tda8026->dev, "CARD EARLY INTERRUPT\n"); + action |= SC_PHY_CARD_ATR_TIMEOUT; + } + + if (status & TDA8026_REG0_PROT_MASK) { + dev_dbg(tda8026->dev, "CARD OVERHEAT/OVERLOAD INTERRUPT\n"); + action |= SC_PHY_CARD_OVERHEAT; + } + + if (action != 0x0 && tda8026->notify) { + /* add slot information. Pass slot-1 as for controller slot + * starts from 0,1,2.. */ + action |= ((slot-1) << SC_PHY_NOTIFICATION_SLOT_SHIFT); + + /* notify action */ + blocking_notifier_call_chain(&tda8026_notifier_list, action, + phy_tda8026->notify_data); + } + return IRQ_HANDLED; +} + +/* + * PDWN bit is set/cleared to apply CLKPD[1:0] bit clock settings to + * the clock pin for the selected card slot. + */ +static int tda8026_pwdn(struct tda8026 *tda8026, u8 slot, int state) +{ + u8 reg0 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + + if (state) + reg0 |= TDA8026_REG0_PDWN_MASK; + else + reg0 &= ~(TDA8026_REG0_PDWN_MASK); + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Set the card supply voltage. + * TDA PHY supports supply voltage of 1.8V, 3V and 5V. + */ +static int tda8026_set_voltage(struct tda8026 *tda8026, u8 slot, int voltage) +{ + u8 reg0 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + + reg0 &= ~(TDA8026_REG0_VCC1V8_MASK | TDA8026_REG0_5V3VN_MASK); + + switch (voltage) { + case SC_PHY_1_8V: + reg0 |= TDA8026_REG0_VCC1V8_MASK; + break; + + case SC_PHY_5V: + reg0 |= TDA8026_REG0_5V3VN_MASK; + break; + + case SC_PHY_3V: + default: + break; + } + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Enable the I/O line by setting I/OEN bit of slot's main address register. + * The I/O line should be enabled prior to card activation. + */ +static int tda8026_io_enable(struct tda8026 *tda8026, u8 slot) +{ + u8 reg0 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 |= TDA8026_REG0_IOEN_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Disable the I/O line by clearing I/OEN bit of slot's main address register. + * The I/O line can be disabled post card activation. + */ +static int tda8026_io_disable(struct tda8026 *tda8026, u8 slot) +{ + u8 reg0 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~(TDA8026_REG0_IOEN_MASK); + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Sets the mute counter in C[15:8] and C[7:0] register + * Write Reg[1:0] = 11 to select C[7:0] register + * Write Reg[1:0] = 10 to select C[15:8] register + */ +static int tda8026_set_atr_mute_time(struct tda8026 *tda8026, u8 slot, + int mute_counter) +{ + u8 reg0; + u8 mute_counter_high = (mute_counter & 0xFF00) >> 8; + u8 mute_counter_low = mute_counter & 0xFF; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 |= TDA8026_REG0_REG10_CLSB_VAL << TDA8026_REG0_REG10_SHIFT; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + /* Write the mute counter value in C[7:0] LSB register */ + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, + &mute_counter_low); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 |= TDA8026_REG0_REG10_CMSB_VAL << TDA8026_REG0_REG10_SHIFT; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + /* Write the mute counter value in C[15:8] MSB register */ + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, + &mute_counter_high); + if (ret < 0) + return ret; + else + return 0; +} + +/* + * Sets the ATR early time counter. + * Write Reg[1:0] = 01 to select D register + */ +static int tda8026_set_atr_early_time(struct tda8026 *tda8026, u8 slot, + int early_counter) +{ + u8 reg0; + int ret = 0; + u8 counter = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 |= TDA8026_REG0_REG10_D_VAL << TDA8026_REG0_REG10_SHIFT; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + /* Write the early atr counter value in D register */ + counter = (early_counter - TDA8026_MIN_EARLY_CYCLE) & 0xFF; + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, &counter); + if (ret < 0) + return ret; + else + return 0; +} + +static int tda8026_set_rstpin(struct tda8026 *tda8026, u8 slot, int state) +{ + u8 reg0 = 0; + u8 reg1 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + /* Write Reg[1:0] = 00 to select CONFIG register */ + reg0 = tda8026->reg0[slot]; + reg0 &= ~TDA8026_REG0_REG10_MASK; + reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) & + TDA8026_REG0_REG10_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + /* Read the Reg1 value */ + ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, + ®1); + if (ret < 0) + return ret; + + if (state) + reg1 |= TDA8026_REG1CFG_RSTIN_MASK; + else + reg1 &= ~TDA8026_REG1CFG_RSTIN_MASK; + + /* Write the Reset value to the register */ + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, ®1); + if (ret < 0) + return ret; + else + return 0; +} + +/* + * Activate the card by setting START bit of slot's main register. + * Voltage selction and enabling of I/O lines should be done prior + * to activating the card. + */ +static int tda8026_activate_card(struct sc_phy *phy_tda8026, u8 slot) +{ + u8 reg0 = 0; + int ret = 0; + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + + /* if PHY is used then RSTIN should be 1 for async cards, + * currently this is applicable only for TDA8026 + */ + tda8026_set_rstpin(tda8026, slot, 1); + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 |= TDA8026_REG0_START_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Deactivate the card by clearing the START bit of slot's main register + * We implement normal de-activation here. + * On clearing the START bit with normal deactivation, automatic + * deactivation is initiated and performaed by TDA8026. + */ +static int tda8026_deactivate_card(struct sc_phy *phy_tda8026, u8 slot) +{ + u8 reg0 = 0; + int ret = 0; + + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~(TDA8026_REG0_START_MASK); + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Warm reset is initiated by setting the WARM bit of slot's main register + */ +static int tda8026_warm_reset(struct sc_phy *phy_tda8026, u8 slot) +{ + u8 reg0 = 0; + int ret = 0; + + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + + /* See section 6.5 in TDA app note */ + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 |= TDA8026_REG0_WARM_RESET_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + return 0; +} + +/* + * Read and return the TDA8026 PHY product version + */ +static int tda8026_get_provider_version(struct tda8026 *tda8026) +{ + u8 val; + u8 version = 0; + int ret = 0; + + /* Select Product version bank i.e Write CSB = 00 */ + val = TDA8026_CSB_PV_INTSTAT_VAL; + ret = tda8026_i2c_write(tda8026, TDA8026_CSB_ADDR, 1, &val); + if (ret < 0) + return ret; + + ret = tda8026_i2c_read(tda8026, TDA8026_PRODVER_ADDR, 1, &version); + if (ret < 0) + return ret; + else + dev_info(tda8026->dev, "Product Version = %x\n", version); + + return version; +} + + +/* + * Set/reset the C4/C8 Pin + * Write Reg[1:0] = 00 to select CONFIG register + */ +static int tda8026_set_c4c8(struct tda8026 *tda8026, + u8 slot, + int state, + int pin) +{ + u8 reg0 = 0; + u8 reg1 = 0; + int ret = 0; + int mask = 0; + + if (slot != 0) { + /* C4/C8 pin value valid only for slot 1 */ + return -EINVAL; + } else { + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~TDA8026_REG0_REG10_MASK; + reg0 |= (TDA8026_REG0_REG10_CFG_VAL << + TDA8026_REG0_REG10_SHIFT) & + TDA8026_REG0_REG10_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, + ®1); + if (ret < 0) + return ret; + if (pin == SC_PHY_PIN_C8) + mask = TDA8026_REG1CFG_C8_MASK; + else if (pin == SC_PHY_PIN_C4) + mask = TDA8026_REG1CFG_C4_MASK; + else + return -EINVAL; + + if (state) + reg1 |= mask; + else + reg1 &= ~mask; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, + ®1); + if (ret < 0) + return ret; + } + return 0; +} + +/* + * Get the state of C4/C8 pin (high/low) + * Write Reg[1:0] = 00 to select CONFIG register + */ +static int tda8026_get_c4c8(struct tda8026 *tda8026, u8 slot, int pin) +{ + u8 reg0 = 0; + u8 reg1 = 0; + int ret = 0; + int mask = 0; + + if (slot != 0) { + /* C4/C8 pin value valid only for slot 1 */ + return -EINVAL; + } else { + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~TDA8026_REG0_REG10_MASK; + reg0 |= (TDA8026_REG0_REG10_CFG_VAL << + TDA8026_REG0_REG10_SHIFT) & + TDA8026_REG0_REG10_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, + ®1); + if (ret < 0) + return ret; + + if (pin == SC_PHY_PIN_C8) + mask = TDA8026_REG1CFG_C8_MASK; + else if (pin == SC_PHY_PIN_C4) + mask = TDA8026_REG1CFG_C4_MASK; + else + return -EINVAL; + + return (reg1 &= mask) ? 1 : 0; + } + return 0; +} + +/* + * Set card clock + * Applicable only for synchronous mode + */ +static int tda8026_set_cardclk(struct tda8026 *tda8026, u8 slot, + int config) +{ + u8 reg0 = 0; + u8 reg1 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~TDA8026_REG0_REG10_MASK; + reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) & + TDA8026_REG0_REG10_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, ®1); + if (ret < 0) + return ret; + + reg1 &= ~(TDA8026_REG1CFG_CLKPD_MASK); + reg1 |= (config << TDA8026_REG1CFG_CLKPD_SHIFT) & + TDA8026_REG1CFG_CLKPD_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, ®1); + if (ret < 0) + return ret; + else + return 0; +} + +/* + * Set the CLKDIV[1:0] bits. + * CLKDIV[1:0] bits define the card clock frequency + * Write Reg[1:0] = 00 to select CONFIG register + */ +static int tda8026_set_clkdiv(struct tda8026 *tda8026, u8 slot, int div) +{ + u8 reg0 = 0; + u8 reg1 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~TDA8026_REG0_REG10_MASK; + reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) & + TDA8026_REG0_REG10_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, ®1); + if (ret < 0) + return ret; + + reg1 &= ~(TDA8026_REG1CFG_CLKDIV_MASK); + reg1 |= (div << TDA8026_REG1CFG_CLKDIV_SHIFT) & + TDA8026_REG1CFG_CLKDIV_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG1_ADDR, 1, ®1); + if (ret < 0) + return ret; + else + return 0; +} + +/* + * Get the CLKDIV[1:0] bits. + * CLKDIV[1:0] bits define the card clock frequency + * Write Reg[1:0] = 00 to select CONFIG register + */ +static int tda8026_get_clkdiv(struct tda8026 *tda8026, u8 slot) +{ + u8 reg0 = 0; + u8 reg1 = 0; + int ret = 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + reg0 = tda8026->reg0[slot]; + reg0 &= ~TDA8026_REG0_REG10_MASK; + reg0 |= (TDA8026_REG0_REG10_CFG_VAL << TDA8026_REG0_REG10_SHIFT) & + TDA8026_REG0_REG10_MASK; + + ret = tda8026_i2c_write(tda8026, TDA8026_REG0_ADDR, 1, ®0); + if (ret < 0) + return ret; + else if (ret == 1) + tda8026->reg0[slot] = reg0; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG1_ADDR, 1, ®1); + if (ret < 0) + return ret; + + ret = reg1 & TDA8026_REG1CFG_CLKDIV_MASK; + + return ret; +} + +/* + * Check if card is present in the slot. + */ +static int tda8026_card_present(struct tda8026 *tda8026, u8 slot) +{ + int present = 0; + int ret = 0; + u8 status = 0; + + if (tda8026->enable == 0) + return 0; + + ret = tda8026_select_slot(tda8026, slot); + if (ret < 0) + return ret; + + ret = tda8026_i2c_read(tda8026, TDA8026_REG0_ADDR, 1, &status); + if (ret < 0) + return ret; + + if (status & TDA8026_REG0_PRES_MASK) + present = 1; + + return present; +} + +/** + * tda8026_register_notify - register a notifier callback whenever a card + * event happens + * @nb: pointer to the notifier block for the callback events. + */ +static int tda8026_register_notify(struct sc_phy *phy_tda8026, + struct notifier_block *nb, void *data) +{ + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + phy_tda8026->notify_data = data; + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + blocking_notifier_chain_register(&tda8026_notifier_list, nb); + tda8026->notify = 1; + return 0; +} + +/** + * tda8026_unregister_notify - unregister a notifier callback + * event happens + * @nb: pointer to the notifier block for the callback events. + */ +static int tda8026_unregister_notify(struct sc_phy *phy_tda8026, + struct notifier_block *nb) +{ + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + blocking_notifier_chain_unregister(&tda8026_notifier_list, nb); + tda8026->notify = 0; + return 0; +} + +static int tda8026_set_config(struct sc_phy *phy_tda8026, u8 slot, enum + sc_phy_config attr, int value) +{ + int ret = 0; + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + switch (attr) { + case SC_PHY_CARD_SUPPLY_VOLTAGE: + ret = tda8026_set_voltage(tda8026, slot, value); + break; + + case SC_PHY_ATR_MUTE_TIME: + ret = tda8026_set_atr_mute_time(tda8026, slot, value); + break; + + case SC_PHY_ATR_EARLY_TIME: + ret = tda8026_set_atr_early_time(tda8026, slot, value); + break; + + case SC_PHY_CARD_MODE: + if (value == SC_PHY_SYNC) { + /* set clkdiv to zero, rst pin to low and pwdn bit to + * logic 0 + */ + tda8026_set_clkdiv(tda8026, slot, 0); + tda8026_set_rstpin(tda8026, slot, 0); + tda8026_pwdn(tda8026, slot, 0); + } else { + /* Nothing to do, default mode is async */ + } + break; + + case SC_PHY_IO: + if (value) + ret = tda8026_io_enable(tda8026, slot); + else + ret = tda8026_io_disable(tda8026, slot); + break; + + case SC_PHY_PIN_RST: + ret = tda8026_set_rstpin(tda8026, slot, value); + break; + + case SC_PHY_CLKDIV: + ret = tda8026_set_clkdiv(tda8026, slot, value); + break; + + case SC_PHY_MODE: + if (value == SC_PHY_ACTIVE) + tda8026_enable(tda8026); + else if (value == SC_PHY_SHUTDOWN) + tda8026_disable(tda8026); + else + ret = -EINVAL; + break; + + case SC_PHY_PIN_C4: + ret = tda8026_set_c4c8(tda8026, slot, value, SC_PHY_PIN_C4); + break; + + case SC_PHY_PIN_C8: + ret = tda8026_set_c4c8(tda8026, slot, value, SC_PHY_PIN_C8); + break; + + case SC_PHY_PIN_CLK: + ret = tda8026_set_cardclk(tda8026, slot, value); + break; + + default: + ret = -EINVAL; + dev_err(phy_tda8026->dev, "operation not supported:%d", attr); + break; + } + return ret; +} + +static int tda8026_get_config(struct sc_phy *phy_tda8026, u8 slot, enum + sc_phy_config attr) +{ + int ret = -1; + struct tda8026 *tda8026; + + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + switch (attr) { + case SC_PHY_CARD_PRESENCE: + ret = tda8026_card_present(tda8026, slot); + break; + + case SC_PHY_VERSION: + ret = tda8026_get_provider_version(tda8026); + break; + + case SC_PHY_CLKDIV: + ret = tda8026_get_clkdiv(tda8026, slot); + break; + + case SC_PHY_PIN_C4: + ret = tda8026_get_c4c8(tda8026, slot, SC_PHY_PIN_C4); + break; + + case SC_PHY_PIN_C8: + ret = tda8026_get_c4c8(tda8026, slot, SC_PHY_PIN_C8); + break; + + default: + ret = -EINVAL; + dev_err(phy_tda8026->dev, "operation not supported:%d", attr); + break; + } + return ret; +} + +#if defined(CONFIG_OF) +static const struct of_device_id tda8026_id_table[]; +#endif + +static int tda8026_parse_dt(struct device *dev, struct tda8026 *pdata) +{ + struct device_node *np = dev->of_node; + int ret = 0; + + pdata->shutdown_gpio = of_get_named_gpio(np, "shutdown-gpio", 0); + if (!gpio_is_valid(pdata->shutdown_gpio)) { + dev_err(dev, "Failed to get shutdown gpio\n"); + return -EINVAL; + } + + ret = devm_gpio_request_one(dev, pdata->shutdown_gpio, + GPIOF_DIR_OUT, "shutdown_gpio"); + if (ret) { + dev_err(dev, "Failed to request shutdown_gpio\n"); + return ret; + } + return 0; +} + +static int tda8026_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret = 0; + struct sc_phy *phy_tda8026; + struct tda8026 *pdata; + + struct device *dev = &i2c->dev; + struct device_node *np = dev->of_node; + + if (np == NULL) + return -EINVAL; + + pdata = devm_kzalloc(dev, sizeof(struct tda8026), GFP_KERNEL); + if (pdata == NULL) + return -ENOMEM; + + phy_tda8026 = devm_kzalloc(dev, sizeof(struct sc_phy), GFP_KERNEL); + if (phy_tda8026 == NULL) + return -ENOMEM; + + ret = tda8026_parse_dt(dev, pdata); + if (ret != 0) + return ret; + + i2c_set_clientdata(i2c, phy_tda8026); + phy_tda8026->dev = &i2c->dev; + + phy_tda8026->pdata = (void *)pdata; + pdata->control_data = i2c; + pdata->irq = i2c->irq; + pdata->dev = phy_tda8026->dev; + pdata->notify = 0; + + if (pdata->irq == 0) + return -EINVAL; + + ret = devm_request_threaded_irq(dev, pdata->irq, NULL, tda8026_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "tda8026", phy_tda8026); + if (ret < 0) { + dev_err(phy_tda8026->dev, "can't get irq %d err %d\n", + pdata->irq, ret); + return ret; + } + + /* enable phy */ + tda8026_enable(pdata); + + tda8026_clear_interrupts(pdata); + phy_tda8026->set_config = tda8026_set_config; + phy_tda8026->get_config = tda8026_get_config; + phy_tda8026->activate_card = tda8026_activate_card; + phy_tda8026->deactivate_card = tda8026_deactivate_card; + phy_tda8026->warm_reset = tda8026_warm_reset; + phy_tda8026->register_notify = tda8026_register_notify; + phy_tda8026->unregister_notify = tda8026_unregister_notify; + + /* disable phy */ + tda8026_disable(pdata); + + return 0; +} + +static int tda8026_i2c_remove(struct i2c_client *i2c) +{ + struct sc_phy *phy_tda8026; + struct tda8026 *tda8026; + int action = 0; + + phy_tda8026 = i2c_get_clientdata(i2c); + if (phy_tda8026 == NULL) + return -EINVAL; + + tda8026 = (struct tda8026 *)phy_tda8026->pdata; + + /* notify action */ + action = SC_PHY_REMOVED; + blocking_notifier_call_chain(&tda8026_notifier_list, action, + phy_tda8026->notify_data); + tda8026->notify = 0; + + /* enable shutdown mode */ + tda8026_disable(tda8026); + + return 0; +} + +#if defined(CONFIG_OF) +static const struct of_device_id tda8026_id_table[] = { + { .compatible = "nxp,tda8026" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tda8026_id_table); +#endif + +static const struct i2c_device_id tda8026_i2c_id[] = { + {"tda8026", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tda8026_i2c_id); + +static struct i2c_driver tda8026_i2c_driver = { + .driver = { + .name = "tda8026", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tda8026_id_table), + }, + .probe = tda8026_i2c_probe, + .remove = tda8026_i2c_remove, + .id_table = tda8026_i2c_id, +}; +static int __init tda8026_i2c_init(void) +{ + int ret; + ret = i2c_add_driver(&tda8026_i2c_driver); + if (ret != 0) + pr_err("Failed to register TDA8026 I2C driver: %d\n", ret); + return ret; +} +/* init early so consumer devices can complete system boot */ +subsys_initcall(tda8026_i2c_init); + +static void __exit tda8026_i2c_exit(void) +{ + i2c_del_driver(&tda8026_i2c_driver); +} +module_exit(tda8026_i2c_exit); + +MODULE_AUTHOR("Maulik Mankad <maulik@ti.com>"); +MODULE_DESCRIPTION("TDA8026 Smart Card NXP PHY driver"); +MODULE_LICENSE("GPL"); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver 2014-05-28 8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel @ 2014-05-28 18:44 ` Greg KH 2014-05-29 8:37 ` Satish Patel 0 siblings, 1 reply; 19+ messages in thread From: Greg KH @ 2014-05-28 18:44 UTC (permalink / raw) To: linux-arm-kernel On Wed, May 28, 2014 at 02:27:14PM +0530, Satish Patel wrote: > TDA8026 is a SmartCard PHY from NXP. > > The PHY interfaces with the main processor over the > I2C interface and acts as a slave device. > > The driver also exposes the phy interface > (defined at include/linux/sc_phy.h) for SmartCard controller. > Controller uses this interface to communicate with smart card > inserted to the phy's slot. > > Note: gpio irq is not validated as I do not have device with that. > I have validated interrupt with dedicated interrupt line on my device. > > Signed-off-by: Satish Patel <satish.patel@ti.com> > --- > Documentation/devicetree/bindings/misc/tda8026.txt | 19 + > drivers/misc/Kconfig | 7 + > drivers/misc/Makefile | 1 + > drivers/misc/tda8026.c | 1258 ++++++++++++++++++++ > 4 files changed, 1285 insertions(+) > create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt > create mode 100644 drivers/misc/tda8026.c > > diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt > new file mode 100644 > index 0000000..f115c9c > --- /dev/null > +++ b/Documentation/devicetree/bindings/misc/tda8026.txt > @@ -0,0 +1,19 @@ > +TDA8026 smart card slot interface > + > +This is an i2c based smart card interface device forming the electrical > +interface between a microcontroller and smart cards. This device supports > +asynchronous cards (micro controller-based IC cards) as well as synchronous > +cards (mainly memory cards) > + > +Required properties: > +- compatible: "nxp,tda8026" > +- shutdown-gpio = GPIO pin mapping for SDWNN pin > +- reg = i2c interface address > + > + > +Example: > +tda8026: tda8026 at 48 { > + compatible = "nxp,tda8026"; > + reg = <0x48>; > + shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */ > + }; > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig > index 8baff0e..80b21d7 100644 > --- a/drivers/misc/Kconfig > +++ b/drivers/misc/Kconfig > @@ -515,6 +515,13 @@ config SRAM > the genalloc API. It is supposed to be used for small on-chip SRAM > areas found on many SoCs. > > +config NXP_TDA8026_PHY > + tristate "NXP PHY Driver for Smart Card PHY" > + depends on I2C=y > + help > + If you say yes here you get support for the TDA8026 Smart card PHY > + with I2C interface. > + > source "drivers/misc/c2port/Kconfig" > source "drivers/misc/eeprom/Kconfig" > source "drivers/misc/cb710/Kconfig" > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile > index 7eb4b69..f262c0b 100644 > --- a/drivers/misc/Makefile > +++ b/drivers/misc/Makefile > @@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o > obj-y += mic/ > obj-$(CONFIG_GENWQE) += genwqe/ > obj-$(CONFIG_ECHO) += echo/ > +obj-$(CONFIG_NXP_TDA8026_PHY) += tda8026.o > diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c > new file mode 100644 > index 0000000..38df33e > --- /dev/null > +++ b/drivers/misc/tda8026.c > @@ -0,0 +1,1258 @@ > +/* > + * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY > + * > + * > + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation version 2. > + * > + * This program is distributed "as is" WITHOUT ANY WARRANTY of any > + * kind, whether express or implied; without even the implied warranty > + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#include <linux/module.h> > +#include <linux/moduleparam.h> > +#include <linux/interrupt.h> > +#include <linux/init.h> > +#include <linux/slab.h> > +#include <linux/gpio.h> > +#include <linux/i2c.h> > +#include <linux/mfd/core.h> > +#include <linux/notifier.h> > +#include <linux/sc_phy.h> > +#include <linux/of_gpio.h> > +#include <linux/of_device.h> > +#include <linux/delay.h> I think you just broke the build if this driver is enabled now right? Not good :( ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver 2014-05-28 18:44 ` Greg KH @ 2014-05-29 8:37 ` Satish Patel 2014-05-29 15:52 ` Greg KH 0 siblings, 1 reply; 19+ messages in thread From: Satish Patel @ 2014-05-29 8:37 UTC (permalink / raw) To: linux-arm-kernel On 5/29/2014 12:14 AM, Greg KH wrote: > On Wed, May 28, 2014 at 02:27:14PM +0530, Satish Patel wrote: >> TDA8026 is a SmartCard PHY from NXP. >> >> The PHY interfaces with the main processor over the >> I2C interface and acts as a slave device. >> >> The driver also exposes the phy interface >> (defined at include/linux/sc_phy.h) for SmartCard controller. >> Controller uses this interface to communicate with smart card >> inserted to the phy's slot. >> >> Note: gpio irq is not validated as I do not have device with that. >> I have validated interrupt with dedicated interrupt line on my device. >> >> Signed-off-by: Satish Patel <satish.patel@ti.com> >> --- >> Documentation/devicetree/bindings/misc/tda8026.txt | 19 + >> drivers/misc/Kconfig | 7 + >> drivers/misc/Makefile | 1 + >> drivers/misc/tda8026.c | 1258 ++++++++++++++++++++ >> 4 files changed, 1285 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt >> create mode 100644 drivers/misc/tda8026.c >> >> diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt >> new file mode 100644 >> index 0000000..f115c9c >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/misc/tda8026.txt >> @@ -0,0 +1,19 @@ >> +TDA8026 smart card slot interface >> + >> +This is an i2c based smart card interface device forming the electrical >> +interface between a microcontroller and smart cards. This device supports >> +asynchronous cards (micro controller-based IC cards) as well as synchronous >> +cards (mainly memory cards) >> + >> +Required properties: >> +- compatible: "nxp,tda8026" >> +- shutdown-gpio = GPIO pin mapping for SDWNN pin >> +- reg = i2c interface address >> + >> + >> +Example: >> +tda8026: tda8026 at 48 { >> + compatible = "nxp,tda8026"; >> + reg = <0x48>; >> + shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */ >> + }; >> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig >> index 8baff0e..80b21d7 100644 >> --- a/drivers/misc/Kconfig >> +++ b/drivers/misc/Kconfig >> @@ -515,6 +515,13 @@ config SRAM >> the genalloc API. It is supposed to be used for small on-chip SRAM >> areas found on many SoCs. >> >> +config NXP_TDA8026_PHY >> + tristate "NXP PHY Driver for Smart Card PHY" >> + depends on I2C=y >> + help >> + If you say yes here you get support for the TDA8026 Smart card PHY >> + with I2C interface. >> + >> source "drivers/misc/c2port/Kconfig" >> source "drivers/misc/eeprom/Kconfig" >> source "drivers/misc/cb710/Kconfig" >> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile >> index 7eb4b69..f262c0b 100644 >> --- a/drivers/misc/Makefile >> +++ b/drivers/misc/Makefile >> @@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o >> obj-y += mic/ >> obj-$(CONFIG_GENWQE) += genwqe/ >> obj-$(CONFIG_ECHO) += echo/ >> +obj-$(CONFIG_NXP_TDA8026_PHY) += tda8026.o >> diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c >> new file mode 100644 >> index 0000000..38df33e >> --- /dev/null >> +++ b/drivers/misc/tda8026.c >> @@ -0,0 +1,1258 @@ >> +/* >> + * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY >> + * >> + * >> + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License as >> + * published by the Free Software Foundation version 2. >> + * >> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any >> + * kind, whether express or implied; without even the implied warranty >> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + */ >> + >> +#include <linux/module.h> >> +#include <linux/moduleparam.h> >> +#include <linux/interrupt.h> >> +#include <linux/init.h> >> +#include <linux/slab.h> >> +#include <linux/gpio.h> >> +#include <linux/i2c.h> >> +#include <linux/mfd/core.h> >> +#include <linux/notifier.h> >> +#include <linux/sc_phy.h> >> +#include <linux/of_gpio.h> >> +#include <linux/of_device.h> >> +#include <linux/delay.h> > > I think you just broke the build if this driver is enabled now right? > > Not good :( Before sending, I have applied these patches to "v3.15-rc7" and build with both the option ti-usim & tda8026 as module, as well as part of kernel. Any specific tree you would like me to rebase these patches against. > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver 2014-05-29 8:37 ` Satish Patel @ 2014-05-29 15:52 ` Greg KH 0 siblings, 0 replies; 19+ messages in thread From: Greg KH @ 2014-05-29 15:52 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 29, 2014 at 02:07:59PM +0530, Satish Patel wrote: > > > On 5/29/2014 12:14 AM, Greg KH wrote: > >On Wed, May 28, 2014 at 02:27:14PM +0530, Satish Patel wrote: > >>TDA8026 is a SmartCard PHY from NXP. > >> > >>The PHY interfaces with the main processor over the > >>I2C interface and acts as a slave device. > >> > >>The driver also exposes the phy interface > >>(defined at include/linux/sc_phy.h) for SmartCard controller. > >>Controller uses this interface to communicate with smart card > >>inserted to the phy's slot. > >> > >>Note: gpio irq is not validated as I do not have device with that. > >>I have validated interrupt with dedicated interrupt line on my device. > >> > >>Signed-off-by: Satish Patel <satish.patel@ti.com> > >>--- > >> Documentation/devicetree/bindings/misc/tda8026.txt | 19 + > >> drivers/misc/Kconfig | 7 + > >> drivers/misc/Makefile | 1 + > >> drivers/misc/tda8026.c | 1258 ++++++++++++++++++++ > >> 4 files changed, 1285 insertions(+) > >> create mode 100644 Documentation/devicetree/bindings/misc/tda8026.txt > >> create mode 100644 drivers/misc/tda8026.c > >> > >>diff --git a/Documentation/devicetree/bindings/misc/tda8026.txt b/Documentation/devicetree/bindings/misc/tda8026.txt > >>new file mode 100644 > >>index 0000000..f115c9c > >>--- /dev/null > >>+++ b/Documentation/devicetree/bindings/misc/tda8026.txt > >>@@ -0,0 +1,19 @@ > >>+TDA8026 smart card slot interface > >>+ > >>+This is an i2c based smart card interface device forming the electrical > >>+interface between a microcontroller and smart cards. This device supports > >>+asynchronous cards (micro controller-based IC cards) as well as synchronous > >>+cards (mainly memory cards) > >>+ > >>+Required properties: > >>+- compatible: "nxp,tda8026" > >>+- shutdown-gpio = GPIO pin mapping for SDWNN pin > >>+- reg = i2c interface address > >>+ > >>+ > >>+Example: > >>+tda8026: tda8026 at 48 { > >>+ compatible = "nxp,tda8026"; > >>+ reg = <0x48>; > >>+ shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;/* Bank5, pin19 */ > >>+ }; > >>diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig > >>index 8baff0e..80b21d7 100644 > >>--- a/drivers/misc/Kconfig > >>+++ b/drivers/misc/Kconfig > >>@@ -515,6 +515,13 @@ config SRAM > >> the genalloc API. It is supposed to be used for small on-chip SRAM > >> areas found on many SoCs. > >> > >>+config NXP_TDA8026_PHY > >>+ tristate "NXP PHY Driver for Smart Card PHY" > >>+ depends on I2C=y > >>+ help > >>+ If you say yes here you get support for the TDA8026 Smart card PHY > >>+ with I2C interface. > >>+ > >> source "drivers/misc/c2port/Kconfig" > >> source "drivers/misc/eeprom/Kconfig" > >> source "drivers/misc/cb710/Kconfig" > >>diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile > >>index 7eb4b69..f262c0b 100644 > >>--- a/drivers/misc/Makefile > >>+++ b/drivers/misc/Makefile > >>@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o > >> obj-y += mic/ > >> obj-$(CONFIG_GENWQE) += genwqe/ > >> obj-$(CONFIG_ECHO) += echo/ > >>+obj-$(CONFIG_NXP_TDA8026_PHY) += tda8026.o > >>diff --git a/drivers/misc/tda8026.c b/drivers/misc/tda8026.c > >>new file mode 100644 > >>index 0000000..38df33e > >>--- /dev/null > >>+++ b/drivers/misc/tda8026.c > >>@@ -0,0 +1,1258 @@ > >>+/* > >>+ * tda8026.c - TDA8026 PHY driver for NXP Smart card PHY > >>+ * > >>+ * > >>+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ > >>+ * > >>+ * This program is free software; you can redistribute it and/or > >>+ * modify it under the terms of the GNU General Public License as > >>+ * published by the Free Software Foundation version 2. > >>+ * > >>+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any > >>+ * kind, whether express or implied; without even the implied warranty > >>+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > >>+ * GNU General Public License for more details. > >>+ */ > >>+ > >>+#include <linux/module.h> > >>+#include <linux/moduleparam.h> > >>+#include <linux/interrupt.h> > >>+#include <linux/init.h> > >>+#include <linux/slab.h> > >>+#include <linux/gpio.h> > >>+#include <linux/i2c.h> > >>+#include <linux/mfd/core.h> > >>+#include <linux/notifier.h> > >>+#include <linux/sc_phy.h> > >>+#include <linux/of_gpio.h> > >>+#include <linux/of_device.h> > >>+#include <linux/delay.h> > > > >I think you just broke the build if this driver is enabled now right? > > > >Not good :( > Before sending, I have applied these patches to "v3.15-rc7" and build with > both the option ti-usim & tda8026 as module, as well as part of kernel. Any > specific tree you would like me to rebase these patches against. Did you try applying the patches one-by-one and building afterwards between each one? In looking at this further, I think it will work, but please test and make sure. You can not break the build with any individual patch. thanks, greg k-h ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim 2014-05-28 8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel 2014-05-28 8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel 2014-05-28 8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel @ 2014-05-28 8:57 ` Satish Patel 2014-05-28 8:57 ` [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy Satish Patel [not found] ` <1401267437-22489-4-git-send-email-satish.patel@ti.com> 4 siblings, 0 replies; 19+ messages in thread From: Satish Patel @ 2014-05-28 8:57 UTC (permalink / raw) To: linux-arm-kernel SoC specific DT entries added for TI's USIM - smart card controller of AM43xx platfrom. Signed-off-by: Satish Patel <satish.patel@ti.com> --- arch/arm/boot/dts/am4372.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index d1f8707..fe830dd 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -735,6 +735,18 @@ #size-cells = <1>; status = "disabled"; }; + + usim0: usim at 48034000 { + compatible = "ti,usim"; + reg = <0x48034000 0x1000>; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; + ti,hwmods = "usim0"; + clocks = <&usim0_opt_fck>, <&usim0_opt_fck32>, + <&dpll_per_m2_div4_ck>; + clock-names = "opt_fck", "opt_fck32", "fck"; + status = "disabled"; + }; + }; }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy 2014-05-28 8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel ` (2 preceding siblings ...) 2014-05-28 8:57 ` [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim Satish Patel @ 2014-05-28 8:57 ` Satish Patel [not found] ` <1401267437-22489-4-git-send-email-satish.patel@ti.com> 4 siblings, 0 replies; 19+ messages in thread From: Satish Patel @ 2014-05-28 8:57 UTC (permalink / raw) To: linux-arm-kernel - Board specific DT entries for TI's USIM - smart card controller of AM43xx platfrom.These entries are used by USIM driver for various configurations. - Shutdown line of NXP phy is maped to GPIO5. So enabling same to have support for NXP phy. - i2c2 pinmux configuration - NxP tda8026 phy is connected to i2c2 lines Signed-off-by: Satish Patel <satish.patel@ti.com> --- arch/arm/boot/dts/am43x-epos-evm.dts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index 167dbc8..ecc8b1a 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -115,6 +115,18 @@ >; }; + usim0_default: usim0_default { + pinctrl-single,pins = < + /* USIM 0 */ + 0x1B4 (SLEWCTRL_FAST | PULL_DISABLE | MUX_MODE8) /* CLK0 */ + 0x1B0 (SLEWCTRL_FAST | PULL_DISABLE | MUX_MODE8) /* CLK1 */ + 0x1B8 (SLEWCTRL_FAST | INPUT_EN | PULL_DISABLE | MUX_MODE8) /* DATA0 */ + 0x1BC (SLEWCTRL_FAST | INPUT_EN | PULL_DISABLE | MUX_MODE8) /* DATA1 */ + 0x1C8 (SLEWCTRL_FAST | INPUT_EN | PULL_UP | MUX_MODE8) /* IRQn */ + >; + }; + + spi0_pins: pinmux_spi0_pins { pinctrl-single,pins = < 0x150 (PIN_INPUT | MUX_MODE0) /* spi0_clk.spi0_clk */ @@ -238,10 +250,24 @@ }; }; +&usim0 { + pinctrl-names = "default"; + pinctrl-0 = <&usim0_default>; + phy = <&tda8026>; + phy-slots = <1>; + status = "okay"; +}; + &i2c2 { pinctrl-names = "default"; pinctrl-0 = <&i2c2_pins>; status = "okay"; + tda8026: tda8026 at 48 { + compatible = "nxp,tda8026"; + reg = <0x48>; + shutdown-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>; /* Bank5, pin19 */ + interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>; + }; }; &gpio0 { @@ -260,6 +286,11 @@ status = "okay"; }; +&gpio5 { + status = "okay"; +}; + + &elm { status = "okay"; }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <1401267437-22489-4-git-send-email-satish.patel@ti.com>]
[parent not found: <CAL_JsqKs=a8GRJRmNE-oxU4imHqnb5szv+Km-wv3KuN0d6Bxkg@mail.gmail.com>]
[parent not found: <53870671.6080601@ti.com>]
* [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx [not found] ` <53870671.6080601@ti.com> @ 2014-05-29 15:53 ` Greg Kroah-Hartman 2014-05-30 4:08 ` Satish Patel 0 siblings, 1 reply; 19+ messages in thread From: Greg Kroah-Hartman @ 2014-05-29 15:53 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 29, 2014 at 03:35:37PM +0530, Satish Patel wrote: > >>+enum usim_card_mode { > >>+ USIM_CARD_MODE_ASYNC = 0, /* asynchronous mode */ > >>+ USIM_CARD_MODE_SYNC_TYPE1, /* synchronous mode: Type 1 */ > >>+ USIM_CARD_MODE_SYNC_TYPE2, /* synchronous mode: Type 2 */ > >>+ USIM_CARD_MODE_SYNC_OTHER, /* Any other synchronous type */ > >>+}; > >>+struct usim_data { > >>+ int slot; > >>+ int rxexplen; > >>+ int txlen; > >>+ unsigned char apdu[256]; > >>+}; You need to use the proper variable types for a structure that is going to cross the user/kernel boundry in an ioctl :( ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx 2014-05-29 15:53 ` [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx Greg Kroah-Hartman @ 2014-05-30 4:08 ` Satish Patel 0 siblings, 0 replies; 19+ messages in thread From: Satish Patel @ 2014-05-30 4:08 UTC (permalink / raw) To: linux-arm-kernel On 5/29/2014 9:23 PM, Greg Kroah-Hartman wrote: > On Thu, May 29, 2014 at 03:35:37PM +0530, Satish Patel wrote: >>>> +enum usim_card_mode { >>>> + USIM_CARD_MODE_ASYNC = 0, /* asynchronous mode */ >>>> + USIM_CARD_MODE_SYNC_TYPE1, /* synchronous mode: Type 1 */ >>>> + USIM_CARD_MODE_SYNC_TYPE2, /* synchronous mode: Type 2 */ >>>> + USIM_CARD_MODE_SYNC_OTHER, /* Any other synchronous type */ >>>> +}; >>>> +struct usim_data { >>>> + int slot; >>>> + int rxexplen; >>>> + int txlen; >>>> + unsigned char apdu[256]; >>>> +}; > > You need to use the proper variable types for a structure that is going > to cross the user/kernel boundry in an ioctl :( Do you mean to use __u32 instead int ? make use of types defined in types.h ? if yes, I will make that change :). Thanks for pointing out. > ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2014-05-30 5:05 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-05-28 8:57 [PATCH v3 0/5] Smart Card(SC) interface, TI USIM & NxP SC phy driver Satish Patel 2014-05-28 8:57 ` [PATCH v3 1/5] sc_phy:SmartCard(SC) PHY interface to SC controller Satish Patel 2014-05-28 18:44 ` Greg KH 2014-05-29 8:56 ` Satish Patel 2014-05-29 15:51 ` Greg KH 2014-05-30 5:05 ` Satish Patel 2014-05-28 18:53 ` Greg KH 2014-05-29 8:34 ` Satish Patel 2014-05-29 13:47 ` Rob Herring 2014-05-29 15:52 ` Greg KH 2014-05-30 3:51 ` Satish Patel 2014-05-28 8:57 ` [PATCH v3 2/5] misc: tda8026: Add NXP TDA8026 PHY driver Satish Patel 2014-05-28 18:44 ` Greg KH 2014-05-29 8:37 ` Satish Patel 2014-05-29 15:52 ` Greg KH 2014-05-28 8:57 ` [PATCH v3 4/5] ARM: dts: AM43xx: DT entries added for ti-usim Satish Patel 2014-05-28 8:57 ` [PATCH v3 5/5] ARM: dts: AM43xx-epos-evm: DT entries for ti-usim and phy Satish Patel [not found] ` <1401267437-22489-4-git-send-email-satish.patel@ti.com> [not found] ` <CAL_JsqKs=a8GRJRmNE-oxU4imHqnb5szv+Km-wv3KuN0d6Bxkg@mail.gmail.com> [not found] ` <53870671.6080601@ti.com> 2014-05-29 15:53 ` [PATCH v3 3/5] char: ti-usim: Add driver for USIM module on AM43xx Greg Kroah-Hartman 2014-05-30 4:08 ` Satish Patel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).