Signed-off-by: Frederic Pecourt <opengemini at free.fr>
Index: target/linux/gemini/image/Makefile
===================================================================
--- target/linux/gemini/image/Makefile (révision 23121)
+++ target/linux/gemini/image/Makefile (copie de travail)
@@ -14,6 +14,9 @@
# WBD222: mach id 2753 (0xAC1)
echo -en "\x0a\x1c\xa0\xe3\xc1\x10\x81\xe3" >
$(KDIR)/$(IMG_PREFIX)-wbd222-zImage
cat $(LINUX_DIR)/arch/arm/boot/zImage >>
$(KDIR)/$(IMG_PREFIX)-wbd222-zImage
+# mzknas: for now same mach id as nas4220b 2038 (0x7F6)
+ echo -en "\x07\x1c\xa0\xe3\xf6\x10\x81\xe3" >
$(KDIR)/$(IMG_PREFIX)-mzknas-zImage
+ cat $(LINUX_DIR)/arch/arm/boot/zImage >>
$(KDIR)/$(IMG_PREFIX)-mzknas-zImage
endef
define Image/BuildKernel
@@ -22,6 +25,8 @@
cat $(KDIR)/$(IMG_PREFIX)-wbd111-zImage >>
$(BIN_DIR)/$(IMG_PREFIX)-wbd111-zImage
echo -en
"\x00\x00\xa0\xe1\x00\x00\xa0\xe1\x00\x00\xa0\xe1\x00\x00\xa0\xe1" >
$(BIN_DIR)/$(IMG_PREFIX)-wbd222-zImage
cat $(KDIR)/$(IMG_PREFIX)-wbd222-zImage >>
$(BIN_DIR)/$(IMG_PREFIX)-wbd222-zImage
+ echo -en
"\x00\x00\xa0\xe1\x00\x00\xa0\xe1\x00\x00\xa0\xe1\x00\x00\xa0\xe1" >
$(BIN_DIR)/$(IMG_PREFIX)-mzknas-zImage
+ cat $(KDIR)/$(IMG_PREFIX)-mzknas-zImage >>
$(BIN_DIR)/$(IMG_PREFIX)-mzknas-zImage
endef
define Image/Build/jffs2-64k
Index: target/linux/gemini/files/arch/arm/mach-gemini/board-mzknas.c
===================================================================
--- target/linux/gemini/files/arch/arm/mach-gemini/board-mzknas.c
(révision 0)
+++ target/linux/gemini/files/arch/arm/mach-gemini/board-mzknas.c
(révision 0)
@@ -0,0 +1,209 @@
+/*
+ * Support for PLANEX MZK-NAS02SG
+ *
+ * Copyright (C) 2010 Frederic PECOURT
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/skbuff.h>
+#include <linux/gpio_keys.h>
+#include <linux/mdio-gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/gmac.h>
+
+#include "common.h"
+#include <mach/hardware.h>
+#include <mach/global_reg.h>
+#define PFLASH_SHARE_BIT 0x02
+
+static struct mdio_gpio_platform_data planex_mdio = {
+ .mdc = 22,
+ .mdio = 21,
+ .phy_mask = ~((1 << 1) | (1 << 2)),
+};
+
+static struct platform_device planex_phy_device = {
+ .name = "mdio-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &planex_mdio,
+ },
+};
+
+static struct gemini_gmac_platform_data gmac_data = {
+ .bus_id[0] = "0:01",
+ .interface[0] = PHY_INTERFACE_MODE_RGMII,
+ .bus_id[1] = "0:02",
+ .interface[1] = PHY_INTERFACE_MODE_RGMII,
+};
+
+static struct gpio_keys_button planex_keys[] = {
+ {
+ .code = KEY_SETUP,
+ .gpio = 61,
+ .active_low = 1,
+ .desc = "Backup Button",
+ .type = EV_KEY,
+ },
+ {
+ .code = KEY_RESTART,
+ .gpio = 63,
+ .active_low = 1,
+ .desc = "Softreset Button",
+ .type = EV_KEY,
+ },
+};
+
+static struct gpio_keys_platform_data planex_keys_data = {
+ .buttons = planex_keys,
+ .nbuttons = ARRAY_SIZE(planex_keys),
+};
+
+static struct platform_device planex_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &planex_keys_data,
+ },
+};
+
+static struct gpio_led planex_leds[] = {
+ {
+ .name = "planex:blue:sata1",
+ .default_trigger = "ata-disk1",
+ .default_state = 1,
+ .gpio = 18,
+ .active_low = 1,
+ },
+ {
+ .name = "planex:blue:sata0",
+ .default_trigger = "ata-disk0",
+ .default_state = 1,
+ .gpio = 17,
+ .active_low = 1,
+ },
+ {
+ .name = "planex:blue:usb2",
+ .default_trigger = "usb2",
+ .default_state = 1,
+ .gpio = 4,
+ .active_low = 1,
+ },
+ {
+ .name = "planex:blue:usb1",
+ .default_trigger = "usb1",
+ .default_state = 1,
+ .gpio = 6,
+ .active_low = 1,
+ },
+ {
+ .name = "planex:blue:power",
+ .default_trigger = "default-on",
+ .default_state = 1,
+ .gpio = 7,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_led_platform_data planex_leds_data = {
+ .num_leds = ARRAY_SIZE(planex_leds),
+ .leds = planex_leds,
+};
+
+static struct platform_device planex_leds_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &planex_leds_data,
+ },
+};
+
+static struct sys_timer planex_timer = {
+ .init = gemini_timer_init,
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition planex_partitions[] = {
+ {
+ .name = "RedBoot",
+ .offset = 0,
+ .size = 0x020000,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "Kernel",
+ .offset = 0x020000,
+ .size = 0x700000,
+ } , {
+ .name = "VCTL",
+ .offset = 0x720000,
+ .size = 0x020000,
+ .mask_flags = MTD_WRITEABLE,
+ } , {
+ .name = "CurConf",
+ .offset = 0x740000,
+ .size = 0x0A0000,
+ /*.mask_flags = MTD_WRITEABLE,*/
+ } , {
+ .name = "FIS",
+ .offset = 0x7E0000,
+ .size = 0x020000,
+ .mask_flags = MTD_WRITEABLE,
+ }
+};
+#define planex_num_partitions ARRAY_SIZE(planex_partitions)
+#else
+#define planex_partitions NULL
+#define planex_num_partitions 0
+#endif /* CONFIG_MTD_PARTITIONS */
+
+static void __init planex_init(void)
+{
+ unsigned int value ;
+
+ gemini_gpio_init();
+ platform_register_uart();
+ platform_register_watchdog();
+#ifdef CONFIG_MTD_PARTITIONS
+ platform_register_pflash(SZ_8M,
planex_partitions,planex_num_partitions);
+#else
+ platform_register_pflash(SZ_8M, NULL,0);
+#endif
+ platform_register_pwc();
+ platform_register_rtc();
+ platform_device_register(&planex_leds_device);
+ platform_device_register(&planex_keys_device);
+ platform_device_register(&planex_phy_device);
+ platform_register_ethernet(&gmac_data);
+ platform_register_usb(0);
+ platform_register_usb(1);
+ platform_register_pata(1);
+ value = readl(IO_ADDRESS((GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL));
+ value = value & (~PFLASH_SHARE_BIT) ;
+ writel(value,IO_ADDRESS((GEMINI_GLOBAL_BASE) +GLOBAL_MISC_CTRL));
+
+}
+
+// for now, no need for a new machine ID
+// which is anyway faked in the boot makefile
+MACHINE_START(NAS4220B, "PLANEX MZK-NAS02SG")
+ .phys_io = 0x7fffc000,
+ .io_pg_offst = ((0xffffc000) >> 18) & 0xfffc,
+ .boot_params = 0x100,
+ .map_io = gemini_map_io,
+ .init_irq = gemini_init_irq,
+ .timer = &planex_timer,
+ .init_machine = planex_init,
+MACHINE_END
Index: target/linux/gemini/files/drivers/ata/pata_gemini.c
===================================================================
--- target/linux/gemini/files/drivers/ata/pata_gemini.c (révision 0)
+++ target/linux/gemini/files/drivers/ata/pata_gemini.c (révision 0)
@@ -0,0 +1,268 @@
+/*
+ * Support for Gemini PATA
+ *
+ * Copyright (C) 2009 Janos Laube <[email protected]>
+ * Copyright (C) 2010 Frederic Pecourt <[email protected]>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Values of IOMUX
+ * 26:24 bits is "IDE IO Select"
+ * 111:100 - Reserved
+ * 011 - ata0 <-> sata0, sata1; bring out ata1
+ * 010 - ata1 <-> sata1, sata0; bring out ata0
+ * 001 - ata0 <-> sata0, ata1 <-> sata1; bring out ata1
+ * 000 - ata0 <-> sata0, ata1 <-> sata1; bring out ata0
+ *
+ */
+
+
+
+
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/leds.h>
+
+#include <mach/hardware.h>
+#include <mach/global_reg.h>
+
+#define DRV_NAME "pata_gemini"
+#define DRV_VERSION "0.11"
+
+#define GEMINI_PATA_PORTS 1
+#define PIO_TIMING_REG (ap->ioaddr.bmdma_addr + 0x10)
+#define MDMA_TIMING_REG (ap->ioaddr.bmdma_addr + 0x11)
+#define UDMA_TIMING0_REG (ap->ioaddr.bmdma_addr + 0x12)
+#define UDMA_TIMING1_REG (ap->ioaddr.bmdma_addr + 0x13)
+#define CLK_MOD_REG (ap->ioaddr.bmdma_addr + 0x14)
+
+static unsigned char PIO_TIMING[5] = {
+ 0xaa, 0xa3, 0xa1, 0x33, 0x31
+};
+
+static unsigned char TIMING_UDMA_50M[6] = {
+ 0x33, 0x31, 0x21, 0x21, 0x11, 0x91
+};
+
+static unsigned char TIMING_UDMA_66M[7] = {
+ 0x44, 0x42, 0x31, 0x21, 0x11, 0x91, 0x91
+};
+
+static struct scsi_host_template gemini_pata_sht = {
+ ATA_NCQ_SHT(DRV_NAME),
+ .can_queue = 1,
+ .sg_tablesize = 128,
+ .dma_boundary = 0xffffU,
+};
+
+static void gemini_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int udma = adev->dma_mode;
+ u8 speed = udma;
+ unsigned int drive_dn = adev->devno;
+ u8 reg;
+
+ reg = ioread8(CLK_MOD_REG);
+ reg |= (1 << (4 + (drive_dn & 0x01)));
+ iowrite8(reg, CLK_MOD_REG);
+
+ if ((speed == XFER_UDMA_6) || (speed == XFER_UDMA_3)
+ || (speed == XFER_UDMA_4) || (speed & XFER_MW_DMA_0))
+ {
+ reg = ioread8(CLK_MOD_REG);
+ reg |= (1 << (drive_dn & 0x01));
+ iowrite8(reg, CLK_MOD_REG);
+ iowrite8(TIMING_UDMA_66M[speed & ~XFER_UDMA_0],
+ UDMA_TIMING0_REG);
+ }
+ else
+ {
+ reg = ioread8(CLK_MOD_REG);
+ reg &= ~(1 << (drive_dn & 0x01));
+ iowrite8(reg, CLK_MOD_REG);
+ iowrite8(TIMING_UDMA_50M[speed & ~XFER_UDMA_0],
+ UDMA_TIMING0_REG);
+ }
+ return;
+}
+
+static void gemini_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ iowrite8(PIO_TIMING[pio], PIO_TIMING_REG);
+}
+
+unsigned int gemini_qc_issue(struct ata_queued_cmd *qc)
+{
+ ledtrig_ide_activity();
+ return ata_sff_qc_issue(qc);
+}
+
+static struct ata_port_operations gemini_pata_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .set_dmamode = gemini_set_dmamode,
+ .set_piomode = gemini_set_piomode,
+ .qc_issue = gemini_qc_issue,
+};
+
+static struct ata_port_info gemini_pata_portinfo = {
+ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_SLAVE_POSS,
+ .udma_mask= ATA_UDMA7,
+ .pio_mask = ATA_PIO4,
+ .port_ops = &gemini_pata_port_ops,
+};
+
+static irqreturn_t gemini_pata_interrupt(int irq, void *dev)
+{
+ struct ata_host *host = dev;
+ unsigned int i, handled = 0;
+
+ spin_lock_irq(&host->lock);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+
+ if (qc && (qc->tf.ctl & ATA_NIEN))
+ ap->ops->sff_check_status(ap);
+ else if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ handled |= ata_sff_host_intr(ap, qc);
+ else
+ ap->ops->sff_check_status(ap);
+ }
+ else
+ ap->ops->sff_check_status(ap);
+ }
+ spin_unlock_irq(&host->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static int gemini_pata_platform_probe(struct platform_device *pdev)
+{
+ struct ata_host *host;
+ struct resource *res;
+ const struct ata_port_info *ppi[] = {&gemini_pata_portinfo, 0};
+ unsigned int irq, i;
+ void __iomem *mmio_base;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res)
+ return -ENODEV;
+ irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ mmio_base = devm_ioremap(&pdev->dev, res->start,
+ res->end - res->start + 1);
+
+ printk("pata_gemini: configuring port with irq %d, base %p\n",
+ irq, mmio_base);
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, GEMINI_PATA_PORTS);
+ if (!host)
+ return -ENOMEM;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ioaddr->bmdma_addr = mmio_base;
+ ioaddr->cmd_addr = mmio_base + 0x20;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = mmio_base + 0x36;
+ ata_sff_std_ports(ioaddr);
+ host->ports[i]->cbl = ATA_CBL_SATA;
+ }
+
+ return ata_host_activate(host, irq, gemini_pata_interrupt,
+ IRQF_SHARED, &gemini_pata_sht);
+}
+
+static int gemini_pata_platform_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ ata_host_detach(host);
+ return 0;
+}
+
+static struct platform_driver gemini_pata_driver = {
+ .probe = gemini_pata_platform_probe,
+ .remove = gemini_pata_platform_remove,
+ .driver = {
+ .name = DRV_NAME,
+ }
+};
+
+static int __init gemini_pata_module_init(void)
+{
+ unsigned int reg;
+ u8 phy_status;
+ unsigned long timeout = jiffies + (HZ * 1);
+
+ /* iomux 2, slave mode */
+ reg = readl(IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL);
+ reg &= ~0x07000000;
+// reg |= 0x02000012;
+ reg |= 0x02000010;
+ writel(reg, IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL);
+
+ /* enabling ports for presence detection */
+ writel(0x00000003, IO_ADDRESS(GEMINI_SATA_BASE) + 0x18);
+ writel(0x00000011, IO_ADDRESS(GEMINI_SATA_BASE) + 0x1c);
+
+ /* disabling port if no drive is present */
+ do
+ {
+ msleep(100);
+ phy_status = readb(IO_ADDRESS(GEMINI_SATA_BASE) + 0x08);
+ if (phy_status & 0x01) break;
+ } while (time_before(jiffies, timeout));
+ if (!(phy_status & 0x01))
+ writel(0x00, IO_ADDRESS(GEMINI_SATA_BASE) + 0x18);
+
+ do
+ {
+ msleep(100);
+ phy_status = readb(IO_ADDRESS(GEMINI_SATA_BASE) + 0x0C);
+ if (phy_status & 0x01) break;
+ } while (time_before(jiffies, timeout));
+ if (!(phy_status & 0x01))
+ writel(0x00, IO_ADDRESS(GEMINI_SATA_BASE) + 0x1C);
+
+ return platform_driver_register(&gemini_pata_driver);
+}
+
+static void __exit gemini_pata_module_exit(void)
+{
+ platform_driver_unregister(&gemini_pata_driver);
+}
+
+module_init(gemini_pata_module_init);
+module_exit(gemini_pata_module_exit);
+
+MODULE_AUTHOR("Janos Laube <[email protected]>");
+MODULE_DESCRIPTION("Parallel ATA driver for Gemini SoC's");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
Index: target/linux/gemini/files/drivers/rtc/rtc-gemini.c
===================================================================
--- target/linux/gemini/files/drivers/rtc/rtc-gemini.c (révision 0)
+++ target/linux/gemini/files/drivers/rtc/rtc-gemini.c (révision 0)
@@ -0,0 +1,247 @@
+/*
+ * Gemini OnChip RTC
+ *
+ * Copyright (C) 2009 Janos Laube <[email protected]>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/rtc.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+
+#define GEMINI_RTC_EPOCH 1970
+
+static const unsigned char days_in_mo[] = {
+ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+struct gemini_rtc
+{
+ struct rtc_device* rtc_dev;
+ void __iomem* rtc_base;
+ int rtc_irq;
+};
+
+enum e_gemini_rtc_offsets
+{
+ GEMINI_RTC_SECOND = 0x00,
+ GEMINI_RTC_MINUTE = 0x04,
+ GEMINI_RTC_HOUR = 0x08,
+ GEMINI_RTC_DAYS = 0x0C,
+ GEMINI_RTC_ALARM_SECOND = 0x10,
+ GEMINI_RTC_ALARM_MINUTE = 0x14,
+ GEMINI_RTC_ALARM_HOUR = 0x18,
+ GEMINI_RTC_RECORD = 0x1C,
+ GEMINI_RTC_CR = 0x20
+};
+
+static irqreturn_t gemini_rtc_interrupt(int irq, void* dev)
+{
+ return IRQ_HANDLED;
+}
+
+static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct gemini_rtc* rtc = dev_get_drvdata(dev);
+
+ unsigned int days;
+ unsigned int months=0;
+ unsigned int years;
+ unsigned int hrs;
+ unsigned int min;
+ unsigned int sec;
+ unsigned int rtc_record;
+ unsigned int total_sec;
+ unsigned int leap_year;
+ unsigned int i;
+
+ sec = ioread32(rtc->rtc_base + GEMINI_RTC_SECOND);
+ min = ioread32(rtc->rtc_base + GEMINI_RTC_MINUTE);
+ hrs = ioread32(rtc->rtc_base + GEMINI_RTC_HOUR);
+ days = ioread32(rtc->rtc_base + GEMINI_RTC_DAYS);
+ rtc_record = ioread32(rtc->rtc_base + GEMINI_RTC_RECORD);
+
+ total_sec = rtc_record + days*86400 + hrs*3600 + min*60 + sec;
+
+ tm->tm_sec = total_sec % 60;
+ tm->tm_min = (total_sec/60) % 60;
+ tm->tm_hour = (total_sec/3600) % 24;
+
+ years = GEMINI_RTC_EPOCH;
+ days = total_sec/86400;
+ while (days > 365)
+ {
+ leap_year = (!(years % 4) && (years % 100)) || !(years % 400);
+ days = days - 365 - leap_year;
+ years++;
+ }
+ leap_year = (!(years % 4) && (years + GEMINI_RTC_EPOCH % 100))
+ || !(years % 400);
+
+ for (i=1;i<=12;i++)
+ {
+ if (days > (days_in_mo[i] + ((i == 2) && leap_year)))
+ days = days - (days_in_mo[i] + ((i == 2) && leap_year));
+ else
+ {
+ months = i;
+ break;
+ }
+ }
+
+ tm->tm_mday = days+1;
+ tm->tm_mon = months-1;
+ tm->tm_year = years-1900;
+ return 0;
+}
+
+static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct gemini_rtc* rtc = dev_get_drvdata(dev);
+ unsigned char mon, day, hrs, min, sec, leap_year;
+ unsigned int years;
+ unsigned int rtc_record;
+ unsigned int rtc_sec,rtc_min,rtc_hour,rtc_day,total_sec;
+
+ years = tm->tm_year + 1900;
+ mon = tm->tm_mon + 1;
+ day = tm->tm_mday;
+ hrs = tm->tm_hour;
+ min = tm->tm_min;
+ sec = tm->tm_sec;
+
+ if (years < GEMINI_RTC_EPOCH)
+ return -EINVAL;
+ if (years >= GEMINI_RTC_EPOCH + 178)
+ return -EINVAL;
+
+ leap_year = ((!(years % 4) && (years % 100)) || !(years % 400));
+ if ((mon > 12) || (day == 0))
+ return -EINVAL;
+ if (day > (days_in_mo[mon] + ((mon == 2) && leap_year)))
+ return -EINVAL;
+ if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+ return -EINVAL;
+
+ rtc_record = mktime(years,mon,day,hrs,min,sec);
+ rtc_record -= mktime(GEMINI_RTC_EPOCH, 1, 1, 0, 0, 0);
+
+ rtc_sec = ioread32(rtc->rtc_base + GEMINI_RTC_SECOND);
+ rtc_min = ioread32(rtc->rtc_base + GEMINI_RTC_MINUTE);
+ rtc_hour = ioread32(rtc->rtc_base + GEMINI_RTC_HOUR);
+ rtc_day = ioread32(rtc->rtc_base + GEMINI_RTC_DAYS);
+ total_sec= rtc_day*86400 + rtc_hour*3600 + rtc_min*60 + rtc_sec;
+
+ iowrite32(rtc_record - total_sec, rtc->rtc_base + GEMINI_RTC_RECORD);
+ iowrite32(0x01, rtc->rtc_base + GEMINI_RTC_CR);
+ return 0;
+}
+
+static struct rtc_class_ops gemini_rtc_ops = {
+ .read_time = gemini_rtc_read_time,
+ .set_time = gemini_rtc_set_time,
+};
+
+static int __devinit gemini_rtc_probe(struct platform_device *pdev)
+{
+ struct gemini_rtc *rtc;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (unlikely(!rtc))
+ return -ENOMEM;
+ platform_set_drvdata(pdev, rtc);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res)
+ {
+ ret = -ENODEV;
+ goto err;
+ }
+ rtc->rtc_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ {
+ ret = -ENODEV;
+ goto err;
+ }
+ rtc->rtc_base = devm_ioremap(&pdev->dev, res->start,
+ res->end - res->start + 1);
+
+ ret = request_irq(rtc->rtc_irq, gemini_rtc_interrupt,
+ IRQF_SHARED, pdev->name, dev);
+
+ if (unlikely(ret))
+ goto err;
+
+ rtc->rtc_dev = rtc_device_register(pdev->name, dev, &gemini_rtc_ops,
+ THIS_MODULE);
+ if (unlikely(IS_ERR(rtc->rtc_dev)))
+ {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err;
+ }
+ return 0;
+
+ err:
+ kfree(rtc);
+ return ret;
+}
+
+static int __devexit gemini_rtc_remove(struct platform_device *pdev)
+{
+ struct gemini_rtc *rtc = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ free_irq(rtc->rtc_irq, dev);
+ rtc_device_unregister(rtc->rtc_dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver gemini_rtc_driver = {
+ .driver = {
+ .name = "rtc-gemini",
+ .owner = THIS_MODULE,
+ },
+ .probe = gemini_rtc_probe,
+ .remove = __devexit_p(gemini_rtc_remove),
+};
+
+static int __init gemini_rtc_init(void)
+{
+ return platform_driver_register(&gemini_rtc_driver);
+}
+
+static void __exit gemini_rtc_exit(void)
+{
+ platform_driver_unregister(&gemini_rtc_driver);
+}
+
+module_init(gemini_rtc_init);
+module_exit(gemini_rtc_exit);
+
+MODULE_AUTHOR("Janos Laube <[email protected]>");
+MODULE_ALIAS("platform:rtc-gemini");
+MODULE_LICENSE("GPL");
Index: target/linux/gemini/files/drivers/misc/gemini_pwc.c
===================================================================
--- target/linux/gemini/files/drivers/misc/gemini_pwc.c (révision 0)
+++ target/linux/gemini/files/drivers/misc/gemini_pwc.c (révision 0)
@@ -0,0 +1,195 @@
+/*
+ * Gemini Power Control driver
+ *
+ * Copyright (C) 2009 Janos Laube <[email protected]>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+
+#define DRV_VERSION 0.1
+
+#define GEMINI_PWC_ID 0x00010500
+#define GEMINI_PWC_IDREG 0x00
+#define GEMINI_PWC_CTRLREG 0x04
+#define GEMINI_PWC_STATREG 0x08
+#define GEMINI_POWERBUTTON 0x40
+
+struct gemini_pwc
+{
+ void __iomem* pwc_base;
+ int pwc_irq;
+};
+
+static spinlock_t pwc_lock;
+/* work around bad designed hardware, the IB-4220-B powerbutton seems not
+ * to be debounced very well
+ */
+static int pwc_poweroff_issued = 0;
+
+static void gemini_power_off(void)
+{
+ unsigned int reg;
+ printk("gemini_pwc: power off\n");
+ reg = readl(IO_ADDRESS(GEMINI_POWER_CTRL_BASE) + GEMINI_PWC_CTRLREG);
+ writel(reg | BIT(2) | BIT(1),
+ IO_ADDRESS(GEMINI_POWER_CTRL_BASE) + GEMINI_PWC_CTRLREG);
+ reg &= ~BIT(1);
+ reg |= BIT(0);
+ writel(reg | BIT(2),
+ IO_ADDRESS(GEMINI_POWER_CTRL_BASE) + GEMINI_PWC_CTRLREG);
+}
+
+static irqreturn_t gemini_pwc_interrupt(int irq, void* dev)
+{
+ unsigned int reg, src;
+
+ spin_lock_irq(&pwc_lock);
+ /* clear pwc interrupt */
+ writel(readl(IO_ADDRESS(GEMINI_POWER_CTRL_BASE) + GEMINI_PWC_CTRLREG)
+ | (1 << 2), IO_ADDRESS(GEMINI_POWER_CTRL_BASE) +
+ GEMINI_PWC_CTRLREG);
+ reg = readl(IO_ADDRESS(GEMINI_INTERRUPT_BASE) + 0x08);
+ reg |= (1 << IRQ_PWR);
+ writel(reg, IO_ADDRESS(GEMINI_INTERRUPT_BASE) + 0x08);
+ barrier();
+
+ src = readl(IO_ADDRESS(GEMINI_POWER_CTRL_BASE) +
+ GEMINI_PWC_STATREG) & 0x70;
+ if ((src == GEMINI_POWERBUTTON) && (!pwc_poweroff_issued))
+ {
+ printk("gemini_pwc: shutting down machine\n");
+ orderly_poweroff(1);
+ pwc_poweroff_issued = 1;
+ }
+ spin_unlock_irq(&pwc_lock);
+ return IRQ_HANDLED;
+}
+
+static int __devinit gemini_pwc_probe(struct platform_device *pdev)
+{
+ struct gemini_pwc *pwc;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+ unsigned int reg;
+
+ pwc = kzalloc(sizeof(struct gemini_pwc), GFP_KERNEL);
+ if (unlikely(!pwc))
+ return -ENOMEM;
+ platform_set_drvdata(pdev, pwc);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res)
+ {
+ ret = -ENODEV;
+ goto err;
+ }
+ pwc->pwc_irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ {
+ ret = -ENODEV;
+ goto err;
+ }
+ pwc->pwc_base = devm_ioremap(&pdev->dev, res->start,
+ res->end - res->start + 1);
+
+ reg = readl(pwc->pwc_base + GEMINI_PWC_IDREG);
+ reg = reg & 0xFFFFFF00;
+ if (reg != GEMINI_PWC_ID)
+ {
+ ret = -ENODEV;
+ goto wrongid;
+ }
+
+ pm_power_off = gemini_power_off;
+
+ /* clear pwc interrupt */
+ writel(readl(pwc->pwc_base + GEMINI_PWC_CTRLREG)
+ | (1 << 2), pwc->pwc_base + GEMINI_PWC_CTRLREG);
+ reg = readl(IO_ADDRESS(GEMINI_INTERRUPT_BASE)+0x08);
+ reg |= (1 << IRQ_PWR);
+ writel(reg, IO_ADDRESS(GEMINI_INTERRUPT_BASE)+0x08);
+ barrier();
+ mdelay(1);
+
+ ret = request_irq(pwc->pwc_irq, gemini_pwc_interrupt, IRQF_DISABLED,
+ pdev->name, dev);
+ if (unlikely(ret))
+ goto err;
+
+ /* enable pwc device */
+ writel(readl(pwc->pwc_base + GEMINI_PWC_CTRLREG)
+ | (1 << 1), pwc->pwc_base + GEMINI_PWC_CTRLREG);
+
+ return 0;
+
+wrongid:
+ printk("gemini_pwc: wrong PWC id\n");
+err:
+ kfree(pwc);
+ return ret;
+}
+
+static int __devexit gemini_pwc_remove(struct platform_device *pdev)
+{
+ struct gemini_pwc *pwc = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ pm_power_off = 0;
+ free_irq(pwc->pwc_irq, dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(pwc);
+
+ return 0;
+}
+
+static struct platform_driver gemini_pwc_driver = {
+ .driver = {
+ .name = "gemini_pwc",
+ .owner = THIS_MODULE,
+ },
+ .probe = gemini_pwc_probe,
+ .remove = __devexit_p(gemini_pwc_remove),
+};
+
+static int __init gemini_pwc_init(void)
+{
+ return platform_driver_register(&gemini_pwc_driver);
+}
+
+static void __exit gemini_pwc_exit(void)
+{
+ platform_driver_unregister(&gemini_pwc_driver);
+}
+
+module_init(gemini_pwc_init);
+module_exit(gemini_pwc_exit);
+
+MODULE_AUTHOR("Janos Laube <[email protected]>");
+MODULE_ALIAS("platform:gemini_pwc");
+MODULE_DESCRIPTION("Driver for the Gemini Power Control device");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel