From 53f5649b21a7c7b894d68ac4848eb01136fa64aa Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Fri, 13 Mar 2009 10:50:17 +0800 Subject: [ARM] pxa: fix typo in BANK_OFF() macro in gpio.h The typo was originally fixed by Mike Rapoport and missed. And is later reported by Matthias Meier. Signed-off-by: Matthias Meier Signed-off-by: Mike Rapoport Signed-off-by: Eric Miao --- arch/arm/mach-pxa/include/mach/gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/include/mach/gpio.h b/arch/arm/mach-pxa/include/mach/gpio.h index 406fa102cb4..c72c89a2285 100644 --- a/arch/arm/mach-pxa/include/mach/gpio.h +++ b/arch/arm/mach-pxa/include/mach/gpio.h @@ -30,7 +30,7 @@ #define GPIO_REGS_VIRT io_p2v(0x40E00000) -#define BANK_OFF(n) (((n) > 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) +#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) #define GPIO_REG(x) (*(volatile u32 *)(GPIO_REGS_VIRT + (x))) /* GPIO Pin Level Registers */ -- cgit v1.2.3 From aac429707df233e9dc7ed70ea04cd29d832dfe61 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 16 Feb 2009 20:40:55 +0300 Subject: [ARM] pxa: add initial support for Cogent CSB726 board Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 8 + arch/arm/mach-pxa/Makefile | 1 + arch/arm/mach-pxa/csb726.c | 318 ++++++++++++++++++++++++++++ arch/arm/mach-pxa/include/mach/csb726.h | 26 +++ arch/arm/mach-pxa/include/mach/uncompress.h | 3 +- 5 files changed, 355 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-pxa/csb726.c create mode 100644 arch/arm/mach-pxa/include/mach/csb726.h (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 33214c1e060..ff1872db5b3 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -393,6 +393,14 @@ config PCM990_DISPLAY_NONE endchoice +config MACH_CSB726 + bool "Enable Cogent CSB726 System On a Module" + select PXA27x + select IWMMXT + help + Say Y here if you intend to run this kernel on a Cogent + CSB726 System On Module. + config PXA_EZX bool "Motorola EZX Platform" select PXA27x diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 361fcfa7531..96a72f02c13 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_MACH_CM_X300) += cm-x300.o obj-$(CONFIG_PXA_EZX) += ezx.o obj-$(CONFIG_MACH_INTELMOTE2) += imote2.o +obj-$(CONFIG_MACH_CSB726) += csb726.o # Support for blinky lights led-y := leds.o diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c new file mode 100644 index 00000000000..2b289f83a61 --- /dev/null +++ b/arch/arm/mach-pxa/csb726.c @@ -0,0 +1,318 @@ +/* + * Support for Cogent CSB726 + * + * Copyright (c) 2008 Dmitry Eremin-Solenikov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "generic.h" +#include "devices.h" + +/* + * n/a: 2, 5, 6, 7, 8, 23, 24, 25, 26, 27, 87, 88, 89, + * nu: 58 -- 77, 90, 91, 93, 102, 105-108, 114-116, + * XXX: 21, + * XXX: 79 CS_3 for LAN9215 or PSKTSEL on R2, R3 + * XXX: 33 CS_5 for LAN9215 on R1 + */ + +static unsigned long csb726_pin_config[] = { + GPIO78_nCS_2, /* EXP_CS */ + GPIO79_nCS_3, /* SMSC9215 */ + GPIO80_nCS_4, /* SM501 */ + + GPIO52_GPIO, /* #SMSC9251 int */ + GPIO53_GPIO, /* SM501 int */ + + GPIO1_GPIO, /* GPIO0 */ + GPIO11_GPIO, /* GPIO1 */ + GPIO9_GPIO, /* GPIO2 */ + GPIO10_GPIO, /* GPIO3 */ + GPIO16_PWM0_OUT, /* or GPIO4 */ + GPIO17_PWM1_OUT, /* or GPIO5 */ + GPIO94_GPIO, /* GPIO6 */ + GPIO95_GPIO, /* GPIO7 */ + GPIO96_GPIO, /* GPIO8 */ + GPIO97_GPIO, /* GPIO9 */ + GPIO15_GPIO, /* EXP_IRQ */ + GPIO18_RDY, /* EXP_WAIT */ + + GPIO0_GPIO, /* PWR_INT */ + GPIO104_GPIO, /* PWR_OFF */ + + GPIO12_GPIO, /* touch irq */ + + GPIO13_SSP2_TXD, + GPIO14_SSP2_SFRM, + MFP_CFG_OUT(GPIO19, AF1, DRIVE_LOW),/* SSP2_SYSCLK */ + GPIO22_SSP2_SCLK, + + GPIO81_SSP3_TXD, + GPIO82_SSP3_RXD, + GPIO83_SSP3_SFRM, + GPIO84_SSP3_SCLK, + + GPIO20_GPIO, /* SDIO int */ + GPIO32_MMC_CLK, + GPIO92_MMC_DAT_0, + GPIO109_MMC_DAT_1, + GPIO110_MMC_DAT_2, + GPIO111_MMC_DAT_3, + GPIO112_MMC_CMD, + GPIO100_GPIO, /* SD CD */ + GPIO101_GPIO, /* SD WP */ + + GPIO28_AC97_BITCLK, + GPIO29_AC97_SDATA_IN_0, + GPIO30_AC97_SDATA_OUT, + GPIO31_AC97_SYNC, + GPIO113_AC97_nRESET, + + GPIO34_FFUART_RXD, + GPIO35_FFUART_CTS, + GPIO36_FFUART_DCD, + GPIO37_FFUART_DSR, + GPIO38_FFUART_RI, + GPIO39_FFUART_TXD, + GPIO40_FFUART_DTR, + GPIO41_FFUART_RTS, + + GPIO42_BTUART_RXD, + GPIO43_BTUART_TXD, + GPIO44_BTUART_CTS, + GPIO45_BTUART_RTS, + + GPIO46_STUART_RXD, + GPIO47_STUART_TXD, + + GPIO48_nPOE, + GPIO49_nPWE, + GPIO50_nPIOR, + GPIO51_nPIOW, + GPIO54_nPCE_2, + GPIO55_nPREG, + GPIO56_nPWAIT, + GPIO57_nIOIS16, /* maybe unused */ + GPIO85_nPCE_1, + GPIO98_GPIO, /* CF IRQ */ + GPIO99_GPIO, /* CF CD */ + GPIO103_GPIO, /* Reset */ + + GPIO117_I2C_SCL, + GPIO118_I2C_SDA, +}; + +static struct pxamci_platform_data csb726_mci_data; + +static int csb726_mci_init(struct device *dev, + irq_handler_t detect, void *data) +{ + int err; + + csb726_mci_data.detect_delay = msecs_to_jiffies(500); + + err = gpio_request(CSB726_GPIO_MMC_DETECT, "MMC detect"); + if (err) + goto err_det_req; + + err = gpio_direction_input(CSB726_GPIO_MMC_DETECT); + if (err) + goto err_det_dir; + + err = gpio_request(CSB726_GPIO_MMC_RO, "MMC ro"); + if (err) + goto err_ro_req; + + err = gpio_direction_input(CSB726_GPIO_MMC_RO); + if (err) + goto err_ro_dir; + + err = request_irq(gpio_to_irq(CSB726_GPIO_MMC_DETECT), detect, + IRQF_DISABLED, "MMC card detect", data); + if (err) + goto err_irq; + + return 0; + +err_irq: +err_ro_dir: + gpio_free(CSB726_GPIO_MMC_RO); +err_ro_req: +err_det_dir: + gpio_free(CSB726_GPIO_MMC_DETECT); +err_det_req: + return err; +} + +static int csb726_mci_get_ro(struct device *dev) +{ + return gpio_get_value(CSB726_GPIO_MMC_RO); +} + +static void csb726_mci_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(CSB726_GPIO_MMC_DETECT), data); + gpio_free(CSB726_GPIO_MMC_RO); + gpio_free(CSB726_GPIO_MMC_DETECT); +} + +static struct pxamci_platform_data csb726_mci = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = csb726_mci_init, + .get_ro = csb726_mci_get_ro, + /* FIXME setpower */ + .exit = csb726_mci_exit, +}; + +static struct pxaohci_platform_data csb726_ohci_platform_data = { + .port_mode = PMM_NPS_MODE, + .flags = ENABLE_PORT1 | NO_OC_PROTECTION, +}; + +static struct mtd_partition csb726_flash_partitions[] = { + { + .name = "Bootloader", + .offset = 0, + .size = CSB726_FLASH_uMON, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "root", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct physmap_flash_data csb726_flash_data = { + .width = 2, + .parts = csb726_flash_partitions, + .nr_parts = ARRAY_SIZE(csb726_flash_partitions), +}; + +static struct resource csb726_flash_resources[] = { + { + .start = PXA_CS0_PHYS, + .end = PXA_CS0_PHYS + CSB726_FLASH_SIZE - 1 , + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device csb726_flash = { + .name = "physmap-flash", + .dev = { + .platform_data = &csb726_flash_data, + }, + .resource = csb726_flash_resources, + .num_resources = ARRAY_SIZE(csb726_flash_resources), +}; + +static struct resource csb726_sm501_resources[] = { + { + .start = PXA_CS4_PHYS, + .end = PXA_CS4_PHYS + SZ_8M - 1, + .flags = IORESOURCE_MEM, + .name = "sm501-localmem", + }, + { + .start = PXA_CS4_PHYS + SZ_64M - SZ_2M, + .end = PXA_CS4_PHYS + SZ_64M - 1, + .flags = IORESOURCE_MEM, + .name = "sm501-regs", + }, + { + .start = CSB726_IRQ_SM501, + .end = CSB726_IRQ_SM501, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sm501_initdata csb726_sm501_initdata = { +/* .devices = SM501_USE_USB_HOST, */ + .devices = SM501_USE_USB_HOST | SM501_USE_UART0 | SM501_USE_UART1, +}; + +static struct sm501_platdata csb726_sm501_platdata = { + .init = &csb726_sm501_initdata, +}; + +static struct platform_device csb726_sm501 = { + .name = "sm501", + .id = 0, + .num_resources = ARRAY_SIZE(csb726_sm501_resources), + .resource = csb726_sm501_resources, + .dev = { + .platform_data = &csb726_sm501_platdata, + }, +}; + +static struct resource csb726_lan_resources[] = { + { + .start = PXA_CS3_PHYS, + .end = PXA_CS3_PHYS + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = CSB726_IRQ_LAN, + .end = CSB726_IRQ_LAN, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device csb726_lan = { + .name = "smc911x", + .id = -1, + .num_resources = ARRAY_SIZE(csb726_lan_resources), + .resource = csb726_lan_resources, +}; + +static struct platform_device *devices[] __initdata = { + &csb726_flash, + &csb726_sm501, + &csb726_lan, +}; + +static void __init csb726_init(void) +{ + pxa2xx_mfp_config(ARRAY_AND_SIZE(csb726_pin_config)); +/* MSC1 = 0x7ffc3ffc; *//* LAN9215/EXP_CS */ +/* MSC2 = 0x06697ff4; *//* none/SM501 */ + MSC2 = (MSC2 & ~0xffff) | 0x7ff4; /* SM501 */ + + pxa_set_i2c_info(NULL); + pxa27x_set_i2c_power_info(NULL); + pxa_set_mci_info(&csb726_mci); + pxa_set_ohci_info(&csb726_ohci_platform_data); + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +MACHINE_START(CSB726, "Cogent CSB726") + .phys_io = 0x40000000, + .boot_params = 0xa0000100, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa27x_init_irq, + .init_machine = csb726_init, + .timer = &pxa_timer, +MACHINE_END diff --git a/arch/arm/mach-pxa/include/mach/csb726.h b/arch/arm/mach-pxa/include/mach/csb726.h new file mode 100644 index 00000000000..747ab1a71f2 --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/csb726.h @@ -0,0 +1,26 @@ +/* + * Support for Cogent CSB726 + * + * Copyright (c) 2008 Dmitry Baryshkov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef CSB726_H +#define CSB726_H + +#define CSB726_GPIO_IRQ_LAN 52 +#define CSB726_GPIO_IRQ_SM501 53 +#define CSB726_GPIO_MMC_DETECT 100 +#define CSB726_GPIO_MMC_RO 101 + +#define CSB726_FLASH_SIZE (64 * 1024 * 1024) +#define CSB726_FLASH_uMON (8 * 1024 * 1024) + +#define CSB726_IRQ_LAN gpio_to_irq(CSB726_GPIO_IRQ_LAN) +#define CSB726_IRQ_SM501 gpio_to_irq(CSB726_GPIO_IRQ_SM501) + +#endif + diff --git a/arch/arm/mach-pxa/include/mach/uncompress.h b/arch/arm/mach-pxa/include/mach/uncompress.h index f4b029c0395..5706cea95d1 100644 --- a/arch/arm/mach-pxa/include/mach/uncompress.h +++ b/arch/arm/mach-pxa/include/mach/uncompress.h @@ -35,7 +35,8 @@ static inline void flush(void) static inline void arch_decomp_setup(void) { - if (machine_is_littleton() || machine_is_intelmote2()) + if (machine_is_littleton() || machine_is_intelmote2() + || machine_is_csb726()) UART = STUART; } -- cgit v1.2.3 From 3b31fabfe258ecc1ffccd01dd186a534d5c804b3 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 16 Feb 2009 20:40:57 +0300 Subject: [ARM] pxa: add support for CSB701 baseboard CSB701 is one of baseboards that can be used with CSB726 SOM. This currently adds support for button and LED on the board. More to come later. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 4 +++ arch/arm/mach-pxa/Makefile | 1 + arch/arm/mach-pxa/csb701.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 arch/arm/mach-pxa/csb701.c (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index ff1872db5b3..d13282d773a 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -401,6 +401,10 @@ config MACH_CSB726 Say Y here if you intend to run this kernel on a Cogent CSB726 System On Module. +config CSB726_CSB701 + bool "Enable supprot for CSB701 baseboard" + depends on MACH_CSB726 + config PXA_EZX bool "Motorola EZX Platform" select PXA27x diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 96a72f02c13..8da8e63d048 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_PXA_EZX) += ezx.o obj-$(CONFIG_MACH_INTELMOTE2) += imote2.o obj-$(CONFIG_MACH_CSB726) += csb726.o +obj-$(CONFIG_CSB726_CSB701) += csb701.o # Support for blinky lights led-y := leds.o diff --git a/arch/arm/mach-pxa/csb701.c b/arch/arm/mach-pxa/csb701.c new file mode 100644 index 00000000000..4a2a2952c37 --- /dev/null +++ b/arch/arm/mach-pxa/csb701.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +static struct gpio_keys_button csb701_buttons[] = { + { + .code = 0x7, + .gpio = 1, + .active_low = 1, + .desc = "SW2", + .type = EV_SW, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data csb701_gpio_keys_data = { + .buttons = csb701_buttons, + .nbuttons = ARRAY_SIZE(csb701_buttons), +}; + +static struct gpio_led csb701_leds[] = { + { + .name = "csb701:yellow:heartbeat", + .default_trigger = "heartbeat", + .gpio = 11, + .active_low = 1, + }, +}; + +static struct platform_device csb701_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev.platform_data = &csb701_gpio_keys_data, +}; + +static struct gpio_led_platform_data csb701_leds_gpio_data = { + .leds = csb701_leds, + .num_leds = ARRAY_SIZE(csb701_leds), +}; + +static struct platform_device csb701_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &csb701_leds_gpio_data, +}; + +static struct platform_device *devices[] __initdata = { + &csb701_gpio_keys, + &csb701_leds_gpio, +}; + +static int __init csb701_init(void) +{ + return platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +module_init(csb701_init); + -- cgit v1.2.3 From 689b4febeca7e98ad1986cf5b036539649cc1a0c Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 30 Jan 2009 20:48:24 +0100 Subject: [ARM] pxa/MioA701: add gpio_vbus driver Add gpio vbus detection to udc driver, by taking advantage of the new gpio_vbus driver. Signed-off-by: Robert Jarzmik Signed-off-by: Eric Miao --- arch/arm/mach-pxa/mioa701.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index e77c95ca67f..735cb94c4a1 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -452,6 +453,12 @@ static void udc_exit(void) mio_gpio_free(ARRAY_AND_SIZE(udc_gpios)); } +struct gpio_vbus_mach_info gpio_vbus_data = { + .gpio_vbus = GPIO13_nUSB_DETECT, + .gpio_vbus_inverted = 1, + .gpio_pullup = -1, +}; + /* * SDIO/MMC Card controller */ @@ -790,6 +797,7 @@ MIO_SIMPLE_DEV(pxa2xx_ac97, "pxa2xx-ac97", NULL) MIO_PARENT_DEV(mio_wm9713_codec, "wm9713-codec", &pxa2xx_ac97.dev, NULL) MIO_SIMPLE_DEV(mioa701_sound, "mioa701-wm9713", NULL) MIO_SIMPLE_DEV(mioa701_board, "mioa701-board", NULL) +MIO_SIMPLE_DEV(gpio_vbus, "gpio-vbus", &gpio_vbus_data); static struct platform_device *devices[] __initdata = { &mioa701_gpio_keys, @@ -801,7 +809,8 @@ static struct platform_device *devices[] __initdata = { &mioa701_sound, &power_dev, &strataflash, - &mioa701_board + &gpio_vbus, + &mioa701_board, }; static void mioa701_machine_exit(void); -- cgit v1.2.3 From cefdb2a4436ec83b4c8b349aa30f976d30c22e25 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 31 Jan 2009 21:07:09 +0100 Subject: [ARM] pxa/MioA701: Migrate after pxa27x_udc gpio_pullup functionality. Signed-off-by: Robert Jarzmik Signed-off-by: Eric Miao --- arch/arm/mach-pxa/mioa701.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index 735cb94c4a1..025772785d3 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -413,21 +413,6 @@ static void gsm_exit(void) /* * USB UDC */ -static void udc_power_command(int cmd) -{ - switch (cmd) { - case PXA2XX_UDC_CMD_DISCONNECT: - gpio_set_value(GPIO22_USB_ENABLE, 0); - break; - case PXA2XX_UDC_CMD_CONNECT: - gpio_set_value(GPIO22_USB_ENABLE, 1); - break; - default: - printk(KERN_INFO "udc_control: unknown command (0x%x)!\n", cmd); - break; - } -} - static int is_usb_connected(void) { return !gpio_get_value(GPIO13_nUSB_DETECT); @@ -435,24 +420,9 @@ static int is_usb_connected(void) static struct pxa2xx_udc_mach_info mioa701_udc_info = { .udc_is_connected = is_usb_connected, - .udc_command = udc_power_command, + .gpio_pullup = GPIO22_USB_ENABLE, }; -struct gpio_ress udc_gpios[] = { - MIO_GPIO_OUT(GPIO22_USB_ENABLE, 0, "USB Vbus enable") -}; - -static int __init udc_init(void) -{ - pxa_set_udc_info(&mioa701_udc_info); - return mio_gpio_request(ARRAY_AND_SIZE(udc_gpios)); -} - -static void udc_exit(void) -{ - mio_gpio_free(ARRAY_AND_SIZE(udc_gpios)); -} - struct gpio_vbus_mach_info gpio_vbus_data = { .gpio_vbus = GPIO13_nUSB_DETECT, .gpio_vbus_inverted = 1, @@ -847,7 +817,7 @@ static void __init mioa701_machine_init(void) pxa_set_mci_info(&mioa701_mci_info); pxa_set_keypad_info(&mioa701_keypad_info); wm97xx_bat_set_pdata(&mioa701_battery_data); - udc_init(); + pxa_set_udc_info(&mioa701_udc_info); pm_power_off = mioa701_poweroff; arm_pm_restart = mioa701_restart; platform_add_devices(devices, ARRAY_SIZE(devices)); @@ -860,7 +830,6 @@ static void __init mioa701_machine_init(void) static void mioa701_machine_exit(void) { - udc_exit(); bootstrap_exit(); gsm_exit(); } -- cgit v1.2.3