2009-06-04 18:35:51

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 0/7] ASIC3 updates

Hi,

here are a few ASIC3 updates, enabling the DS1WM (w1/master) and
SDIO/MMC (mmc/host) cells. Patch 1 adds functions to change EXTCF
and SDHWCTRL registers, which will also be needed for PCMCIA.

I tried to write the clock handling code in patch 2 in a way that should
make it easy to convert to the clk API, if we'll ever get a common struct
clk oder clkops across architectures.

Patch 5 removes the unneeded SD/SDIO controller register definitions,
since the tmio_mmc driver should take care of that.

regards
Philipp


2009-06-04 18:36:05

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 1/7] MFD: ASIC3: add API for EXTCF and SDHWCTRL register manipulation

Those registers are needed for PCMCIA and MMC/SDIO operation as
well as for the DS1WM.

Signed-off-by: Philipp Zabel <[email protected]>
---
drivers/mfd/asic3.c | 48 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/asic3.h | 13 +++++++----
2 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 9e48545..8e1653a 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -52,6 +52,54 @@ static inline u32 asic3_read_register(struct asic3 *asic,
(reg >> asic->bus_shift));
}

+void asic3_set_extcf_select(struct device *dev, u32 bits, int value)
+{
+ struct asic3 *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic->lock, flags);
+ v = asic3_read_register(asic, ASIC3_OFFSET(EXTCF, SELECT));
+ if (value)
+ v |= bits;
+ else
+ v &= ~bits;
+ asic3_write_register(asic, ASIC3_OFFSET(EXTCF, SELECT), v);
+ spin_unlock_irqrestore(&asic->lock, flags);
+}
+EXPORT_SYMBOL(asic3_set_extcf_select);
+
+void asic3_set_extcf_reset(struct device *dev, u32 bits, int value)
+{
+ struct asic3 *asic = dev->driver_data;
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic->lock, flags);
+ v = asic3_read_register(asic, ASIC3_OFFSET(EXTCF, RESET));
+ if (value)
+ v |= bits;
+ else
+ v &= ~bits;
+ asic3_write_register(asic, ASIC3_OFFSET(EXTCF, RESET), v);
+ spin_unlock_irqrestore(&asic->lock, flags);
+}
+
+void asic3_set_sdhwctrl(struct asic3 *asic, u32 bits, int value)
+{
+ unsigned long flags;
+ u32 v;
+
+ spin_lock_irqsave(&asic->lock, flags);
+ v = asic3_read_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF));
+ if (value)
+ v |= bits;
+ else
+ v &= ~bits;
+ asic3_write_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), v);
+ spin_unlock_irqrestore(&asic->lock, flags);
+}
+
/* IRQs */
#define MAX_ASIC_ISR_LOOPS 20
#define ASIC3_GPIO_BASE_INCR \
diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index 322cd6d..cd02d20 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -16,6 +16,9 @@

#include <linux/types.h>

+/* for PCMCIA */
+extern void asic3_set_extcf_select(struct device *dev, u32 bits, int value);
+
struct asic3_platform_data {
u16 *gpio_config;
unsigned int gpio_config_num;
@@ -227,8 +230,8 @@ struct asic3_platform_data {


/* Basic control of the SD ASIC */
-#define ASIC3_SDHWCTRL_Base 0x0E00
-#define ASIC3_SDHWCTRL_SDConf 0x00
+#define ASIC3_SDHWCTRL_BASE 0x0E00
+#define ASIC3_SDHWCTRL_SDCONF 0x00

#define ASIC3_SDHWCTRL_SUSPEND (1 << 0) /* 1=suspend all SD operations */
#define ASIC3_SDHWCTRL_CLKSEL (1 << 1) /* 1=SDICK, 0=HCLK */
@@ -242,10 +245,10 @@ struct asic3_platform_data {
/* SD card power supply ctrl 1=enable */
#define ASIC3_SDHWCTRL_SDPWR (1 << 6)

-#define ASIC3_EXTCF_Base 0x1100
+#define ASIC3_EXTCF_BASE 0x1100

-#define ASIC3_EXTCF_Select 0x00
-#define ASIC3_EXTCF_Reset 0x04
+#define ASIC3_EXTCF_SELECT 0x00
+#define ASIC3_EXTCF_RESET 0x04

#define ASIC3_EXTCF_SMOD0 (1 << 0) /* slot number of mode 0 */
#define ASIC3_EXTCF_SMOD1 (1 << 1) /* slot number of mode 1 */
--
1.6.3.1

2009-06-04 18:36:45

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 4/7] MFD: ASIC3: use resource_size macro instead of local variable

This should make the code a little bit easier to read.

Signed-off-by: Philipp Zabel <[email protected]>
---
drivers/mfd/asic3.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index ed7f0c1..a2a446d 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -656,7 +656,6 @@ static int __init asic3_probe(struct platform_device *pdev)
struct asic3 *asic;
struct resource *mem;
unsigned long clksel;
- int map_size;
int ret = 0;

asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
@@ -676,8 +675,7 @@ static int __init asic3_probe(struct platform_device *pdev)
goto out_free;
}

- map_size = mem->end - mem->start + 1;
- asic->mapping = ioremap(mem->start, map_size);
+ asic->mapping = ioremap(mem->start, resource_size(mem));
if (!asic->mapping) {
ret = -ENOMEM;
dev_err(asic->dev, "Couldn't ioremap\n");
@@ -687,7 +685,7 @@ static int __init asic3_probe(struct platform_device *pdev)
asic->irq_base = pdata->irq_base;

/* calculate bus shift from mem resource */
- asic->bus_shift = 2 - (map_size >> 12);
+ asic->bus_shift = 2 - (resource_size(mem) >> 12);

clksel = 0;
asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel);
--
1.6.3.1

2009-06-04 18:36:33

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 3/7] MFD: ASIC3: add ASIC3 IRQ numbers

IRQ number definitions for PWM, LED, SPI and OWM (ds1wm).

Signed-off-by: Philipp Zabel <[email protected]>
---
include/linux/mfd/asic3.h | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index cd02d20..5fc3aa4 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -33,6 +33,13 @@ struct asic3_platform_data {
#define ASIC3_NUM_GPIOS 64
#define ASIC3_NR_IRQS ASIC3_NUM_GPIOS + 6

+#define ASIC3_IRQ_LED0 64
+#define ASIC3_IRQ_LED1 65
+#define ASIC3_IRQ_LED2 66
+#define ASIC3_IRQ_SPI 67
+#define ASIC3_IRQ_SMBUS 68
+#define ASIC3_IRQ_OWM 69
+
#define ASIC3_TO_GPIO(gpio) (NR_BUILTIN_GPIO + (gpio))

#define ASIC3_GPIO_BANK_A 0
--
1.6.3.1

2009-06-04 18:36:22

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 2/7] MFD: ASIC3: add clock handling for MFD cells

Since ASIC3 has to work on both PXA and S3C and since their
struct clk implementations differ, we can't register out
clocks with the clkdev mechanism (yet?).
For now we have to keep clock handling internal to this
driver and enable/disable the clocks via the
mfd_cell->enable/disable functions.

Signed-off-by: Philipp Zabel <[email protected]>
---
drivers/mfd/asic3.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 8e1653a..ed7f0c1 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -25,6 +25,48 @@

#include <linux/mfd/asic3.h>

+enum {
+ ASIC3_CLOCK_SPI,
+ ASIC3_CLOCK_OWM,
+ ASIC3_CLOCK_PWM0,
+ ASIC3_CLOCK_PWM1,
+ ASIC3_CLOCK_LED0,
+ ASIC3_CLOCK_LED1,
+ ASIC3_CLOCK_LED2,
+ ASIC3_CLOCK_SD_HOST,
+ ASIC3_CLOCK_SD_BUS,
+ ASIC3_CLOCK_SMBUS,
+ ASIC3_CLOCK_EX0,
+ ASIC3_CLOCK_EX1,
+};
+
+struct asic3_clk {
+ int enabled;
+ unsigned int cdex;
+ unsigned long rate;
+};
+
+#define INIT_CDEX(_name, _rate) \
+ [ASIC3_CLOCK_##_name] = { \
+ .cdex = CLOCK_CDEX_##_name, \
+ .rate = _rate, \
+ }
+
+struct asic3_clk asic3_clk_init[] __initdata = {
+ INIT_CDEX(SPI, 0),
+ INIT_CDEX(OWM, 5000000),
+ INIT_CDEX(PWM0, 0),
+ INIT_CDEX(PWM1, 0),
+ INIT_CDEX(LED0, 0),
+ INIT_CDEX(LED1, 0),
+ INIT_CDEX(LED2, 0),
+ INIT_CDEX(SD_HOST, 24576000),
+ INIT_CDEX(SD_BUS, 12288000),
+ INIT_CDEX(SMBUS, 0),
+ INIT_CDEX(EX0, 32768),
+ INIT_CDEX(EX1, 24576000),
+};
+
struct asic3 {
void __iomem *mapping;
unsigned int bus_shift;
@@ -34,6 +76,8 @@ struct asic3 {
u16 irq_bothedge[4];
struct gpio_chip gpio;
struct device *dev;
+
+ struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
};

static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
@@ -573,6 +617,37 @@ static int asic3_gpio_remove(struct platform_device *pdev)
return gpiochip_remove(&asic->gpio);
}

+static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
+{
+ unsigned long flags;
+ u32 cdex;
+
+ spin_lock_irqsave(&asic->lock, flags);
+ if (clk->enabled++ == 0) {
+ cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
+ cdex |= clk->cdex;
+ asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
+ }
+ spin_unlock_irqrestore(&asic->lock, flags);
+
+ return 0;
+}
+
+static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
+{
+ unsigned long flags;
+ u32 cdex;
+
+ WARN_ON(clk->enabled == 0);
+
+ spin_lock_irqsave(&asic->lock, flags);
+ if (--clk->enabled == 0) {
+ cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
+ cdex &= ~clk->cdex;
+ asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
+ }
+ spin_unlock_irqrestore(&asic->lock, flags);
+}

/* Core */
static int __init asic3_probe(struct platform_device *pdev)
@@ -638,6 +713,11 @@ static int __init asic3_probe(struct platform_device *pdev)
goto out_irq;
}

+ /* Making a per-device copy is only needed for the
+ * theoretical case of multiple ASIC3s on one board:
+ */
+ memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
+
dev_info(asic->dev, "ASIC3 Core driver\n");

return 0;
--
1.6.3.1

2009-06-04 18:37:11

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 5/7] MFD: ASIC3: remove SD/SDIO controller register definitions

Only the base addresses remain, as they are needed to set up
the IOMEM resources.

Signed-off-by: Philipp Zabel <[email protected]>
---
include/linux/mfd/asic3.h | 219 +--------------------------------------------
1 files changed, 3 insertions(+), 216 deletions(-)

diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index 5fc3aa4..8019f67 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -289,222 +289,9 @@ struct asic3_platform_data {
* SDIO_CTRL Control registers for SDIO operations
*
*****************************************************************************/
-#define ASIC3_SD_CONFIG_Base 0x0400 /* Assumes 32 bit addressing */
-
-#define ASIC3_SD_CONFIG_Command 0x08 /* R/W: Command */
-
-/* [0:8] SD Control Register Base Address */
-#define ASIC3_SD_CONFIG_Addr0 0x20
-
-/* [9:31] SD Control Register Base Address */
-#define ASIC3_SD_CONFIG_Addr1 0x24
-
-/* R/O: interrupt assigned to pin */
-#define ASIC3_SD_CONFIG_IntPin 0x78
-
-/*
- * Set to 0x1f to clock SD controller, 0 otherwise.
- * At 0x82 - Gated Clock Ctrl
- */
-#define ASIC3_SD_CONFIG_ClkStop 0x80
-
-/* Control clock of SD controller */
-#define ASIC3_SD_CONFIG_ClockMode 0x84
-#define ASIC3_SD_CONFIG_SDHC_PinStatus 0x88 /* R/0: SD pins status */
-#define ASIC3_SD_CONFIG_SDHC_Power1 0x90 /* Power1 - manual pwr ctrl */
-
-/* auto power up after card inserted */
-#define ASIC3_SD_CONFIG_SDHC_Power2 0x92
-
-/* auto power down when card removed */
-#define ASIC3_SD_CONFIG_SDHC_Power3 0x94
-#define ASIC3_SD_CONFIG_SDHC_CardDetect 0x98
-#define ASIC3_SD_CONFIG_SDHC_Slot 0xA0 /* R/O: support slot number */
-#define ASIC3_SD_CONFIG_SDHC_ExtGateClk1 0x1E0 /* Not used */
-#define ASIC3_SD_CONFIG_SDHC_ExtGateClk2 0x1E2 /* Not used*/
-
-/* GPIO Output Reg. , at 0x1EA - GPIO Output Enable Reg. */
-#define ASIC3_SD_CONFIG_SDHC_GPIO_OutAndEnable 0x1E8
-#define ASIC3_SD_CONFIG_SDHC_GPIO_Status 0x1EC /* GPIO Status Reg. */
-
-/* Bit 1: double buffer/single buffer */
-#define ASIC3_SD_CONFIG_SDHC_ExtGateClk3 0x1F0
-
-/* Memory access enable (set to 1 to access SD Controller) */
-#define SD_CONFIG_COMMAND_MAE (1<<1)
-
-#define SD_CONFIG_CLK_ENABLE_ALL 0x1f
-
-#define SD_CONFIG_POWER1_PC_33V 0x0200 /* Set for 3.3 volts */
-#define SD_CONFIG_POWER1_PC_OFF 0x0000 /* Turn off power */
-
- /* two bits - number of cycles for card detection */
-#define SD_CONFIG_CARDDETECTMODE_CLK ((x) & 0x3)
-
-
-#define ASIC3_SD_CTRL_Base 0x1000
-
-#define ASIC3_SD_CTRL_Cmd 0x00
-#define ASIC3_SD_CTRL_Arg0 0x08
-#define ASIC3_SD_CTRL_Arg1 0x0C
-#define ASIC3_SD_CTRL_StopInternal 0x10
-#define ASIC3_SD_CTRL_TransferSectorCount 0x14
-#define ASIC3_SD_CTRL_Response0 0x18
-#define ASIC3_SD_CTRL_Response1 0x1C
-#define ASIC3_SD_CTRL_Response2 0x20
-#define ASIC3_SD_CTRL_Response3 0x24
-#define ASIC3_SD_CTRL_Response4 0x28
-#define ASIC3_SD_CTRL_Response5 0x2C
-#define ASIC3_SD_CTRL_Response6 0x30
-#define ASIC3_SD_CTRL_Response7 0x34
-#define ASIC3_SD_CTRL_CardStatus 0x38
-#define ASIC3_SD_CTRL_BufferCtrl 0x3C
-#define ASIC3_SD_CTRL_IntMaskCard 0x40
-#define ASIC3_SD_CTRL_IntMaskBuffer 0x44
-#define ASIC3_SD_CTRL_CardClockCtrl 0x48
-#define ASIC3_SD_CTRL_MemCardXferDataLen 0x4C
-#define ASIC3_SD_CTRL_MemCardOptionSetup 0x50
-#define ASIC3_SD_CTRL_ErrorStatus0 0x58
-#define ASIC3_SD_CTRL_ErrorStatus1 0x5C
-#define ASIC3_SD_CTRL_DataPort 0x60
-#define ASIC3_SD_CTRL_TransactionCtrl 0x68
-#define ASIC3_SD_CTRL_SoftwareReset 0x1C0
-
-#define SD_CTRL_SOFTWARE_RESET_CLEAR (1<<0)
-
-#define SD_CTRL_TRANSACTIONCONTROL_SET (1<<8)
-
-#define SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD (1<<15)
-#define SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK (1<<8)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_512 (1<<7)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_256 (1<<6)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_128 (1<<5)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_64 (1<<4)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_32 (1<<3)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_16 (1<<2)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_8 (1<<1)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_4 (1<<0)
-#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_2 (0<<0)
-
-#define MEM_CARD_OPTION_REQUIRED 0x000e
-#define MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(x) (((x) & 0x0f) << 4)
-#define MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT (1<<14)
-#define MEM_CARD_OPTION_DATA_XFR_WIDTH_1 (1<<15)
-#define MEM_CARD_OPTION_DATA_XFR_WIDTH_4 0
-
-#define SD_CTRL_COMMAND_INDEX(x) ((x) & 0x3f)
-#define SD_CTRL_COMMAND_TYPE_CMD (0 << 6)
-#define SD_CTRL_COMMAND_TYPE_ACMD (1 << 6)
-#define SD_CTRL_COMMAND_TYPE_AUTHENTICATION (2 << 6)
-#define SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL (0 << 8)
-#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1 (4 << 8)
-#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B (5 << 8)
-#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2 (6 << 8)
-#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3 (7 << 8)
-#define SD_CTRL_COMMAND_DATA_PRESENT (1 << 11)
-#define SD_CTRL_COMMAND_TRANSFER_READ (1 << 12)
-#define SD_CTRL_COMMAND_TRANSFER_WRITE (0 << 12)
-#define SD_CTRL_COMMAND_MULTI_BLOCK (1 << 13)
-#define SD_CTRL_COMMAND_SECURITY_CMD (1 << 14)
-
-#define SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12 (1 << 0)
-#define SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12 (1 << 8)
-
-#define SD_CTRL_CARDSTATUS_RESPONSE_END (1 << 0)
-#define SD_CTRL_CARDSTATUS_RW_END (1 << 2)
-#define SD_CTRL_CARDSTATUS_CARD_REMOVED_0 (1 << 3)
-#define SD_CTRL_CARDSTATUS_CARD_INSERTED_0 (1 << 4)
-#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_0 (1 << 5)
-#define SD_CTRL_CARDSTATUS_WRITE_PROTECT (1 << 7)
-#define SD_CTRL_CARDSTATUS_CARD_REMOVED_3 (1 << 8)
-#define SD_CTRL_CARDSTATUS_CARD_INSERTED_3 (1 << 9)
-#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_3 (1 << 10)
-
-#define SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR (1 << 0)
-#define SD_CTRL_BUFFERSTATUS_CRC_ERROR (1 << 1)
-#define SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR (1 << 2)
-#define SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT (1 << 3)
-#define SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW (1 << 4)
-#define SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW (1 << 5)
-#define SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT (1 << 6)
-#define SD_CTRL_BUFFERSTATUS_UNK7 (1 << 7)
-#define SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE (1 << 8)
-#define SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE (1 << 9)
-#define SD_CTRL_BUFFERSTATUS_ILLEGAL_FUNCTION (1 << 13)
-#define SD_CTRL_BUFFERSTATUS_CMD_BUSY (1 << 14)
-#define SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS (1 << 15)
-
-#define SD_CTRL_INTMASKCARD_RESPONSE_END (1 << 0)
-#define SD_CTRL_INTMASKCARD_RW_END (1 << 2)
-#define SD_CTRL_INTMASKCARD_CARD_REMOVED_0 (1 << 3)
-#define SD_CTRL_INTMASKCARD_CARD_INSERTED_0 (1 << 4)
-#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 (1 << 5)
-#define SD_CTRL_INTMASKCARD_UNK6 (1 << 6)
-#define SD_CTRL_INTMASKCARD_WRITE_PROTECT (1 << 7)
-#define SD_CTRL_INTMASKCARD_CARD_REMOVED_3 (1 << 8)
-#define SD_CTRL_INTMASKCARD_CARD_INSERTED_3 (1 << 9)
-#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 (1 << 10)
-
-#define SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR (1 << 0)
-#define SD_CTRL_INTMASKBUFFER_CRC_ERROR (1 << 1)
-#define SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR (1 << 2)
-#define SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT (1 << 3)
-#define SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW (1 << 4)
-#define SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW (1 << 5)
-#define SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT (1 << 6)
-#define SD_CTRL_INTMASKBUFFER_UNK7 (1 << 7)
-#define SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE (1 << 8)
-#define SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE (1 << 9)
-#define SD_CTRL_INTMASKBUFFER_ILLEGAL_FUNCTION (1 << 13)
-#define SD_CTRL_INTMASKBUFFER_CMD_BUSY (1 << 14)
-#define SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS (1 << 15)
-
-#define SD_CTRL_DETAIL0_RESPONSE_CMD_ERROR (1 << 0)
-#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 2)
-#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_CMD12 (1 << 3)
-#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_READ_DATA (1 << 4)
-#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_WRITE_CRC_STATUS (1 << 5)
-#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 8)
-#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_CMD12 (1 << 9)
-#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_READ_DATA (1 << 10)
-#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_WRITE_CMD (1 << 11)
-
-#define SD_CTRL_DETAIL1_NO_CMD_RESPONSE (1 << 0)
-#define SD_CTRL_DETAIL1_TIMEOUT_READ_DATA (1 << 4)
-#define SD_CTRL_DETAIL1_TIMEOUT_CRS_STATUS (1 << 5)
-#define SD_CTRL_DETAIL1_TIMEOUT_CRC_BUSY (1 << 6)
-
-#define ASIC3_SDIO_CTRL_Base 0x1200
-
-#define ASIC3_SDIO_CTRL_Cmd 0x00
-#define ASIC3_SDIO_CTRL_CardPortSel 0x04
-#define ASIC3_SDIO_CTRL_Arg0 0x08
-#define ASIC3_SDIO_CTRL_Arg1 0x0C
-#define ASIC3_SDIO_CTRL_TransferBlockCount 0x14
-#define ASIC3_SDIO_CTRL_Response0 0x18
-#define ASIC3_SDIO_CTRL_Response1 0x1C
-#define ASIC3_SDIO_CTRL_Response2 0x20
-#define ASIC3_SDIO_CTRL_Response3 0x24
-#define ASIC3_SDIO_CTRL_Response4 0x28
-#define ASIC3_SDIO_CTRL_Response5 0x2C
-#define ASIC3_SDIO_CTRL_Response6 0x30
-#define ASIC3_SDIO_CTRL_Response7 0x34
-#define ASIC3_SDIO_CTRL_CardStatus 0x38
-#define ASIC3_SDIO_CTRL_BufferCtrl 0x3C
-#define ASIC3_SDIO_CTRL_IntMaskCard 0x40
-#define ASIC3_SDIO_CTRL_IntMaskBuffer 0x44
-#define ASIC3_SDIO_CTRL_CardXferDataLen 0x4C
-#define ASIC3_SDIO_CTRL_CardOptionSetup 0x50
-#define ASIC3_SDIO_CTRL_ErrorStatus0 0x54
-#define ASIC3_SDIO_CTRL_ErrorStatus1 0x58
-#define ASIC3_SDIO_CTRL_DataPort 0x60
-#define ASIC3_SDIO_CTRL_TransactionCtrl 0x68
-#define ASIC3_SDIO_CTRL_CardIntCtrl 0x6C
-#define ASIC3_SDIO_CTRL_ClocknWaitCtrl 0x70
-#define ASIC3_SDIO_CTRL_HostInformation 0x74
-#define ASIC3_SDIO_CTRL_ErrorCtrl 0x78
-#define ASIC3_SDIO_CTRL_LEDCtrl 0x7C
-#define ASIC3_SDIO_CTRL_SoftwareReset 0x1C0
+#define ASIC3_SD_CONFIG_BASE 0x0400 /* Assumes 32 bit addressing */
+#define ASIC3_SD_CTRL_BASE 0x1000
+#define ASIC3_SDIO_CTRL_BASE 0x1200

#define ASIC3_MAP_SIZE_32BIT 0x2000
#define ASIC3_MAP_SIZE_16BIT 0x1000
--
1.6.3.1

2009-06-04 18:37:30

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 6/7] MFD: ASIC3: enable DS1WM cell.

This enables the ASIC3's DS1WM MFD cell, supported by the ds1wm driver.

Signed-off-by: Philipp Zabel <[email protected]>
---
drivers/mfd/Kconfig | 1 +
drivers/mfd/asic3.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ee3927a..9e6d5ee 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -30,6 +30,7 @@ config MFD_SM501_GPIO
config MFD_ASIC3
bool "Support for Compaq ASIC3"
depends on GENERIC_HARDIRQS && GPIOLIB && ARM
+ select MFD_CORE
---help---
This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones)
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index a2a446d..cfe8b32 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -17,6 +17,7 @@
*/

#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/io.h>
@@ -24,6 +25,8 @@
#include <linux/platform_device.h>

#include <linux/mfd/asic3.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ds1wm.h>

enum {
ASIC3_CLOCK_SPI,
@@ -649,6 +652,97 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
spin_unlock_irqrestore(&asic->lock, flags);
}

+/* MFD cells (SPI, PWM, DS1WM, MMC) */
+static struct ds1wm_driver_data ds1wm_pdata = {
+ .active_high = 1,
+};
+
+static struct resource ds1wm_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = ASIC3_IRQ_OWM,
+ .start = ASIC3_IRQ_OWM,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+};
+
+static int ds1wm_enable(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ struct asic3 *asic = dev->driver_data;
+
+ /* Turn on external clocks and the OWM clock */
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]);
+ msleep(1);
+
+ asic3_set_extcf_reset(dev, ASIC3_EXTCF_OWM_RESET, 1);
+ msleep(1);
+ asic3_set_extcf_reset(dev, ASIC3_EXTCF_OWM_RESET, 0);
+ msleep(1);
+
+ /* Clear OWM_SMB, set OWM_EN */
+ asic3_set_extcf_select(dev, ASIC3_EXTCF_OWM_EN, 1);
+ msleep(1);
+
+ return 0;
+}
+
+static int ds1wm_disable(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ struct asic3 *asic = dev->driver_data;
+
+ asic3_set_extcf_select(dev, ASIC3_EXTCF_OWM_EN, 0);
+
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_OWM]);
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
+
+ return 0;
+}
+
+static struct mfd_cell asic3_cell_ds1wm = {
+ .name = "ds1wm",
+ .enable = ds1wm_enable,
+ .disable = ds1wm_disable,
+ .driver_data = &ds1wm_pdata,
+ .num_resources = ARRAY_SIZE(ds1wm_resources),
+ .resources = ds1wm_resources,
+};
+
+static int __init asic3_mfd_probe(struct platform_device *pdev,
+ struct resource *mem)
+{
+ struct asic3 *asic = platform_get_drvdata(pdev);
+ int ret;
+
+ /* DS1WM */
+ asic3_set_extcf_select(&pdev->dev, ASIC3_EXTCF_OWM_SMB, 0);
+
+ ds1wm_resources[0].start = ASIC3_OWM_BASE >> asic->bus_shift;
+ ds1wm_resources[0].end = ds1wm_resources[0].start
+ + (5 << (2 - asic->bus_shift)) - 1;
+
+ asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm;
+ asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
+
+ ret = mfd_add_devices(&pdev->dev, pdev->id,
+ &asic3_cell_ds1wm, 1, mem, asic->irq_base);
+
+ return ret;
+}
+
+static void asic3_mfd_remove(struct platform_device *pdev)
+{
+ struct asic3 *asic = platform_get_drvdata(pdev);
+
+ mfd_remove_devices(&pdev->dev);
+}
+
/* Core */
static int __init asic3_probe(struct platform_device *pdev)
{
@@ -716,6 +810,8 @@ static int __init asic3_probe(struct platform_device *pdev)
*/
memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));

+ asic3_mfd_probe(pdev, mem);
+
dev_info(asic->dev, "ASIC3 Core driver\n");

return 0;
@@ -737,6 +833,8 @@ static int asic3_remove(struct platform_device *pdev)
int ret;
struct asic3 *asic = platform_get_drvdata(pdev);

+ asic3_mfd_remove(pdev);
+
ret = asic3_gpio_remove(pdev);
if (ret < 0)
return ret;
--
1.6.3.1

2009-06-04 18:37:58

by Philipp Zabel

[permalink] [raw]
Subject: [PATCH 7/7] MFD: ASIC3: enable SD/SDIO cell

This enables the ASIC3's SD/SDIO MFD cell, supported by the tmio_mmc driver.

Signed-off-by: Philipp Zabel <[email protected]>
---
drivers/mfd/asic3.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index cfe8b32..f25cc1e 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -27,6 +27,7 @@
#include <linux/mfd/asic3.h>
#include <linux/mfd/core.h>
#include <linux/mfd/ds1wm.h>
+#include <linux/mfd/tmio.h>

enum {
ASIC3_CLOCK_SPI,
@@ -714,11 +715,101 @@ static struct mfd_cell asic3_cell_ds1wm = {
.resources = ds1wm_resources,
};

+static struct tmio_mmc_data asic3_mmc_data = {
+ .hclk = 24576000,
+};
+
+static struct resource asic3_mmc_resources[] = {
+ {
+ .start = ASIC3_SD_CTRL_BASE,
+ .end = ASIC3_SD_CTRL_BASE + 0x3ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = ASIC3_SD_CONFIG_BASE,
+ .end = ASIC3_SD_CONFIG_BASE + 0x1ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int asic3_mmc_enable(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ struct asic3 *asic = dev->driver_data;
+
+ /* Not sure if it must be done bit by bit, but leaving as-is */
+ asic3_set_sdhwctrl(asic, ASIC3_SDHWCTRL_LEVCD, 1);
+ asic3_set_sdhwctrl(asic, ASIC3_SDHWCTRL_LEVWP, 1);
+ asic3_set_sdhwctrl(asic, ASIC3_SDHWCTRL_SUSPEND, 0);
+ asic3_set_sdhwctrl(asic, ASIC3_SDHWCTRL_PCLR, 0);
+
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
+ /* CLK32 used for card detection and for interruption detection
+ * when HCLK is stopped.
+ */
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
+ msleep(1);
+
+ /* HCLK 24.576 MHz, BCLK 12.288 MHz: */
+ asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL),
+ CLOCK_SEL_CX | CLOCK_SEL_SD_HCLK_SEL);
+
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]);
+ asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]);
+ msleep(1);
+
+ asic3_set_extcf_select(dev, ASIC3_EXTCF_SD_MEM_ENABLE, 1);
+
+ /* Enable SD card slot 3.3V power supply */
+ asic3_set_sdhwctrl(asic, ASIC3_SDHWCTRL_SDPWR, 1);
+
+ return 0;
+}
+
+static int asic3_mmc_disable(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ struct asic3 *asic = dev->driver_data;
+
+ /* Put in suspend mode */
+ asic3_set_sdhwctrl(asic, ASIC3_SDHWCTRL_SUSPEND, 1);
+
+ /* Disable clocks */
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]);
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]);
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
+ asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
+ return 0;
+}
+
+static struct mfd_cell asic3_cell_mmc = {
+ .name = "tmio-mmc",
+ .enable = asic3_mmc_enable,
+ .disable = asic3_mmc_disable,
+ .driver_data = &asic3_mmc_data,
+ .num_resources = ARRAY_SIZE(asic3_mmc_resources),
+ .resources = asic3_mmc_resources,
+};
+
static int __init asic3_mfd_probe(struct platform_device *pdev,
struct resource *mem)
{
struct asic3 *asic = platform_get_drvdata(pdev);
- int ret;
+ struct resource *mem_sdio;
+ int irq, ret;
+
+ mem_sdio = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!mem_sdio)
+ dev_dbg(asic->dev, "no SDIO MEM resource\n");
+
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0)
+ dev_dbg(asic->dev, "no SDIO IRQ resource\n");

/* DS1WM */
asic3_set_extcf_select(&pdev->dev, ASIC3_EXTCF_OWM_SMB, 0);
@@ -730,16 +821,30 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm;
asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);

+ /* MMC */
+ asic3_mmc_resources[0].start >>= (2 - asic->bus_shift);
+ asic3_mmc_resources[0].end >>= (2 - asic->bus_shift);
+ asic3_mmc_resources[1].start >>= (2 - asic->bus_shift);
+ asic3_mmc_resources[1].end >>= (2 - asic->bus_shift);
+
+ asic3_cell_mmc.platform_data = &asic3_cell_mmc;
+ asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
+
ret = mfd_add_devices(&pdev->dev, pdev->id,
&asic3_cell_ds1wm, 1, mem, asic->irq_base);
+ if (ret < 0)
+ goto out;

+ if (mem_sdio && (irq >= 0))
+ ret = mfd_add_devices(&pdev->dev, pdev->id,
+ &asic3_cell_mmc, 1, mem_sdio, irq);
+
+ out:
return ret;
}

static void asic3_mfd_remove(struct platform_device *pdev)
{
- struct asic3 *asic = platform_get_drvdata(pdev);
-
mfd_remove_devices(&pdev->dev);
}

--
1.6.3.1

2009-06-04 23:44:24

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH 1/7] MFD: ASIC3: add API for EXTCF and SDHWCTRL register manipulation

Hi Philipp

On Thu, Jun 04, 2009 at 08:36:10PM +0200, Philipp Zabel wrote:
> Those registers are needed for PCMCIA and MMC/SDIO operation as
> well as for the DS1WM.
>
> Signed-off-by: Philipp Zabel <[email protected]>
> ---
> drivers/mfd/asic3.c | 48 +++++++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/asic3.h | 13 +++++++----
> 2 files changed, 56 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
> index 9e48545..8e1653a 100644
> --- a/drivers/mfd/asic3.c
> +++ b/drivers/mfd/asic3.c
> @@ -52,6 +52,54 @@ static inline u32 asic3_read_register(struct asic3 *asic,
> (reg >> asic->bus_shift));
> }
>
> +void asic3_set_extcf_select(struct device *dev, u32 bits, int value)
2 remarks here:
- The "value" parameter could be a bool, and could use a better name, e.g.
"set".
- Those 3 routines are basically doing the same thing. Why not having a
generic:
void asic3_set_register(struct device *dev, u32 reg, u32 bits, bool set) ?

Cheers,
Samuel.

> +{
> + struct asic3 *asic = dev->driver_data;
> + unsigned long flags;
> + u32 v;
> +
> + spin_lock_irqsave(&asic->lock, flags);
> + v = asic3_read_register(asic, ASIC3_OFFSET(EXTCF, SELECT));
> + if (value)
> + v |= bits;
> + else
> + v &= ~bits;
> + asic3_write_register(asic, ASIC3_OFFSET(EXTCF, SELECT), v);
> + spin_unlock_irqrestore(&asic->lock, flags);
> +}
> +EXPORT_SYMBOL(asic3_set_extcf_select);
> +
> +void asic3_set_extcf_reset(struct device *dev, u32 bits, int value)
> +{
> + struct asic3 *asic = dev->driver_data;
> + unsigned long flags;
> + u32 v;
> +
> + spin_lock_irqsave(&asic->lock, flags);
> + v = asic3_read_register(asic, ASIC3_OFFSET(EXTCF, RESET));
> + if (value)
> + v |= bits;
> + else
> + v &= ~bits;
> + asic3_write_register(asic, ASIC3_OFFSET(EXTCF, RESET), v);
> + spin_unlock_irqrestore(&asic->lock, flags);
> +}
> +
> +void asic3_set_sdhwctrl(struct asic3 *asic, u32 bits, int value)
> +{
> + unsigned long flags;
> + u32 v;
> +
> + spin_lock_irqsave(&asic->lock, flags);
> + v = asic3_read_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF));
> + if (value)
> + v |= bits;
> + else
> + v &= ~bits;
> + asic3_write_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), v);
> + spin_unlock_irqrestore(&asic->lock, flags);
> +}
> +
> /* IRQs */
> #define MAX_ASIC_ISR_LOOPS 20
> #define ASIC3_GPIO_BASE_INCR \
> diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
> index 322cd6d..cd02d20 100644
> --- a/include/linux/mfd/asic3.h
> +++ b/include/linux/mfd/asic3.h
> @@ -16,6 +16,9 @@
>
> #include <linux/types.h>
>
> +/* for PCMCIA */
> +extern void asic3_set_extcf_select(struct device *dev, u32 bits, int value);
> +
> struct asic3_platform_data {
> u16 *gpio_config;
> unsigned int gpio_config_num;
> @@ -227,8 +230,8 @@ struct asic3_platform_data {
>
>
> /* Basic control of the SD ASIC */
> -#define ASIC3_SDHWCTRL_Base 0x0E00
> -#define ASIC3_SDHWCTRL_SDConf 0x00
> +#define ASIC3_SDHWCTRL_BASE 0x0E00
> +#define ASIC3_SDHWCTRL_SDCONF 0x00
>
> #define ASIC3_SDHWCTRL_SUSPEND (1 << 0) /* 1=suspend all SD operations */
> #define ASIC3_SDHWCTRL_CLKSEL (1 << 1) /* 1=SDICK, 0=HCLK */
> @@ -242,10 +245,10 @@ struct asic3_platform_data {
> /* SD card power supply ctrl 1=enable */
> #define ASIC3_SDHWCTRL_SDPWR (1 << 6)
>
> -#define ASIC3_EXTCF_Base 0x1100
> +#define ASIC3_EXTCF_BASE 0x1100
>
> -#define ASIC3_EXTCF_Select 0x00
> -#define ASIC3_EXTCF_Reset 0x04
> +#define ASIC3_EXTCF_SELECT 0x00
> +#define ASIC3_EXTCF_RESET 0x04
>
> #define ASIC3_EXTCF_SMOD0 (1 << 0) /* slot number of mode 0 */
> #define ASIC3_EXTCF_SMOD1 (1 << 1) /* slot number of mode 1 */
> --
> 1.6.3.1
>

--
Intel Open Source Technology Centre
http://oss.intel.com/

2009-06-04 23:47:17

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH 2/7] MFD: ASIC3: add clock handling for MFD cells

Hi Philipp,

On Thu, Jun 04, 2009 at 08:36:11PM +0200, Philipp Zabel wrote:
> +
> +struct asic3_clk {
> + int enabled;
You probably want to use a kref here.

> +static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
> +{
> + unsigned long flags;
> + u32 cdex;
> +
> + spin_lock_irqsave(&asic->lock, flags);
> + if (clk->enabled++ == 0) {
using the kref API here would definitely be nicer.

Cheers,
Samuel.

> + cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
> + cdex |= clk->cdex;
> + asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
> + }
> + spin_unlock_irqrestore(&asic->lock, flags);
> +
> + return 0;
> +}
> +
> +static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
> +{
> + unsigned long flags;
> + u32 cdex;
> +
> + WARN_ON(clk->enabled == 0);
> +
> + spin_lock_irqsave(&asic->lock, flags);
> + if (--clk->enabled == 0) {
> + cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
> + cdex &= ~clk->cdex;
> + asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
> + }
> + spin_unlock_irqrestore(&asic->lock, flags);
> +}
>
> /* Core */
> static int __init asic3_probe(struct platform_device *pdev)
> @@ -638,6 +713,11 @@ static int __init asic3_probe(struct platform_device *pdev)
> goto out_irq;
> }
>
> + /* Making a per-device copy is only needed for the
> + * theoretical case of multiple ASIC3s on one board:
> + */
> + memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
> +
> dev_info(asic->dev, "ASIC3 Core driver\n");
>
> return 0;
> --
> 1.6.3.1
>

--
Intel Open Source Technology Centre
http://oss.intel.com/

2009-06-05 16:25:43

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH 1/7] MFD: ASIC3: add API for EXTCF and SDHWCTRL register manipulation

Hi Samuel,

On Fri, Jun 5, 2009 at 1:46 AM, Samuel Ortiz<[email protected]> wrote:
> Hi Philipp
>
> On Thu, Jun 04, 2009 at 08:36:10PM +0200, Philipp Zabel wrote:
>> Those registers are needed for PCMCIA and MMC/SDIO operation as
>> well as for the DS1WM.
>>
>> Signed-off-by: Philipp Zabel <[email protected]>
>> ---
>> ?drivers/mfd/asic3.c ? ? ? | ? 48 +++++++++++++++++++++++++++++++++++++++++++++
>> ?include/linux/mfd/asic3.h | ? 13 +++++++----
>> ?2 files changed, 56 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
>> index 9e48545..8e1653a 100644
>> --- a/drivers/mfd/asic3.c
>> +++ b/drivers/mfd/asic3.c
>> @@ -52,6 +52,54 @@ static inline u32 asic3_read_register(struct asic3 *asic,
>> ? ? ? ? ? ? ? ? ? ? ? (reg >> asic->bus_shift));
>> ?}
>>
>> +void asic3_set_extcf_select(struct device *dev, u32 bits, int value)
> 2 remarks here:
> - The "value" parameter could be a bool, and could use a better name, e.g.
> "set".
> - Those 3 routines are basically doing the same thing. Why not having a
> generic:
> void asic3_set_register(struct device *dev, u32 reg, u32 bits, bool set) ?

Thanks. The reasoning behind this split (besides the fact that the
hh.org driver did it this way) was that only asic3_set_extcf_select
has to be exported for the pcmcia driver and I'd like to move the
register addresses from the public header into asic3.c or into a
private header some time.

I think it is better to have one (unexported) function as you suggest
and then export a custom function to handle the EXTCF
SLEEP_MODE/BUF_EN/PWAIT_EN bits in the future.

Will combine and resend.

> Cheers,
> Samuel.
>
>> +{
>> + ? ? struct asic3 *asic = dev->driver_data;
>> + ? ? unsigned long flags;
>> + ? ? u32 v;
>> +
>> + ? ? spin_lock_irqsave(&asic->lock, flags);
>> + ? ? v = asic3_read_register(asic, ASIC3_OFFSET(EXTCF, SELECT));
>> + ? ? if (value)
>> + ? ? ? ? ? ? v |= bits;
>> + ? ? else
>> + ? ? ? ? ? ? v &= ~bits;
>> + ? ? asic3_write_register(asic, ASIC3_OFFSET(EXTCF, SELECT), v);
>> + ? ? spin_unlock_irqrestore(&asic->lock, flags);
>> +}
>> +EXPORT_SYMBOL(asic3_set_extcf_select);
>> +
>> +void asic3_set_extcf_reset(struct device *dev, u32 bits, int value)
>> +{
>> + ? ? struct asic3 *asic = dev->driver_data;
>> + ? ? unsigned long flags;
>> + ? ? u32 v;
>> +
>> + ? ? spin_lock_irqsave(&asic->lock, flags);
>> + ? ? v = asic3_read_register(asic, ASIC3_OFFSET(EXTCF, RESET));
>> + ? ? if (value)
>> + ? ? ? ? ? ? v |= bits;
>> + ? ? else
>> + ? ? ? ? ? ? v &= ~bits;
>> + ? ? asic3_write_register(asic, ASIC3_OFFSET(EXTCF, RESET), v);
>> + ? ? spin_unlock_irqrestore(&asic->lock, flags);
>> +}
>> +
>> +void asic3_set_sdhwctrl(struct asic3 *asic, u32 bits, int value)
>> +{
>> + ? ? unsigned long flags;
>> + ? ? u32 v;
>> +
>> + ? ? spin_lock_irqsave(&asic->lock, flags);
>> + ? ? v = asic3_read_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF));
>> + ? ? if (value)
>> + ? ? ? ? ? ? v |= bits;
>> + ? ? else
>> + ? ? ? ? ? ? v &= ~bits;
>> + ? ? asic3_write_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), v);
>> + ? ? spin_unlock_irqrestore(&asic->lock, flags);
>> +}
>> +
>> ?/* IRQs */
>> ?#define MAX_ASIC_ISR_LOOPS ? ?20
>> ?#define ASIC3_GPIO_BASE_INCR \
>> diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
>> index 322cd6d..cd02d20 100644
>> --- a/include/linux/mfd/asic3.h
>> +++ b/include/linux/mfd/asic3.h
>> @@ -16,6 +16,9 @@
>>
>> ?#include <linux/types.h>
>>
>> +/* for PCMCIA */
>> +extern void asic3_set_extcf_select(struct device *dev, u32 bits, int value);
>> +
>> ?struct asic3_platform_data {
>> ? ? ? u16 *gpio_config;
>> ? ? ? unsigned int gpio_config_num;
>> @@ -227,8 +230,8 @@ struct asic3_platform_data {
>>
>>
>> ?/* Basic control of the SD ASIC */
>> -#define ASIC3_SDHWCTRL_Base ?0x0E00
>> -#define ASIC3_SDHWCTRL_SDConf ? ?0x00
>> +#define ASIC3_SDHWCTRL_BASE ? ? 0x0E00
>> +#define ASIC3_SDHWCTRL_SDCONF ? ? 0x00
>>
>> ?#define ASIC3_SDHWCTRL_SUSPEND ? ?(1 << 0) ?/* 1=suspend all SD operations */
>> ?#define ASIC3_SDHWCTRL_CLKSEL ? ? (1 << 1) ?/* 1=SDICK, 0=HCLK */
>> @@ -242,10 +245,10 @@ struct asic3_platform_data {
>> ?/* SD card power supply ctrl 1=enable */
>> ?#define ASIC3_SDHWCTRL_SDPWR ? ? ?(1 << 6)
>>
>> -#define ASIC3_EXTCF_Base ? ? ? ? ? ? 0x1100
>> +#define ASIC3_EXTCF_BASE ? ? ? ?0x1100
>>
>> -#define ASIC3_EXTCF_Select ? ? ? ? 0x00
>> -#define ASIC3_EXTCF_Reset ? ? ? ? ?0x04
>> +#define ASIC3_EXTCF_SELECT ? ? ? ?0x00
>> +#define ASIC3_EXTCF_RESET ? ? ? ? 0x04
>>
>> ?#define ASIC3_EXTCF_SMOD0 ? ? ? ? ? ? (1 << 0) ?/* slot number of mode 0 */
>> ?#define ASIC3_EXTCF_SMOD1 ? ? ? ? ? ? (1 << 1) ?/* slot number of mode 1 */
>> --
>> 1.6.3.1
>>
>
> --
> Intel Open Source Technology Centre
> http://oss.intel.com/
>

2009-06-05 16:27:30

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH 2/7] MFD: ASIC3: add clock handling for MFD cells

On Fri, Jun 5, 2009 at 1:49 AM, Samuel Ortiz<[email protected]> wrote:
> Hi Philipp,
>
> On Thu, Jun 04, 2009 at 08:36:11PM +0200, Philipp Zabel wrote:
>> +
>> +struct asic3_clk {
>> + ? ? int enabled;
> You probably want to use a kref here.
>
>> +static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
>> +{
>> + ? ? unsigned long flags;
>> + ? ? u32 cdex;
>> +
>> + ? ? spin_lock_irqsave(&asic->lock, flags);
>> + ? ? if (clk->enabled++ == 0) {
> using the kref API here would definitely be nicer.

While I agree that the kref API looks nice, I'm not convinced it is
intended to be used in this case. We are not counting references here.
There is no way to get the count back from the API, which we need to
decide whether or not to flip the CDEX bits. We could misuse the
release function pointer given to kref_put to turn off the clock, but
I'd prefer to leave it the way it is now.

regards
Philipp

2009-06-05 16:56:18

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH 2/7] MFD: ASIC3: add clock handling for MFD cells

On Fri, Jun 05, 2009 at 06:27:20PM +0200, pHilipp Zabel wrote:
> On Fri, Jun 5, 2009 at 1:49 AM, Samuel Ortiz<[email protected]> wrote:
> > Hi Philipp,
> >
> > On Thu, Jun 04, 2009 at 08:36:11PM +0200, Philipp Zabel wrote:
> >> +
> >> +struct asic3_clk {
> >> + ? ? int enabled;
> > You probably want to use a kref here.
> >
> >> +static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
> >> +{
> >> + ? ? unsigned long flags;
> >> + ? ? u32 cdex;
> >> +
> >> + ? ? spin_lock_irqsave(&asic->lock, flags);
> >> + ? ? if (clk->enabled++ == 0) {
> > using the kref API here would definitely be nicer.
>
> While I agree that the kref API looks nice, I'm not convinced it is
> intended to be used in this case. We are not counting references here.
> There is no way to get the count back from the API, which we need to
> decide whether or not to flip the CDEX bits.
Fair enough.


> We could misuse the
> release function pointer given to kref_put to turn off the clock, but
> I'd prefer to leave it the way it is now.
That's fine with me.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/