From 1f378030cca4bbc6985de711d4e83fc090425d7b Mon Sep 17 00:00:00 2001 From: vitalogy Date: Tue, 19 Jan 2016 07:02:02 +0100 Subject: [PATCH 1/3] dt-overlay: add wittypi-overlay.dts --- .../arm/boot/dts/overlays/wittypi-overlay.dts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/wittypi-overlay.dts diff --git a/arch/arm/boot/dts/overlays/wittypi-overlay.dts b/arch/arm/boot/dts/overlays/wittypi-overlay.dts new file mode 100644 index 00000000000000..be5987db5d2756 --- /dev/null +++ b/arch/arm/boot/dts/overlays/wittypi-overlay.dts @@ -0,0 +1,44 @@ +/* + * Device Tree overlay for Witty Pi extension board by UUGear + * + */ + +/dts-v1/; +/plugin/; + +/ { + + compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + + fragment@0 { + target = <&leds>; + __overlay__ { + compatible = "gpio-leds"; + wittypi_led: wittypi_led { + label = "wittypi_led"; + linux,default-trigger = "default-on"; + gpios = <&gpio 17 0>; + }; + }; + }; + + fragment@1 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + rtc: ds1337@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + wakeup-source; + }; + }; + }; + + __overrides__ { + led_gpio = <&wittypi_led>,"gpios:4"; + led_trigger = <&wittypi_led>,"linux,default-trigger"; + }; + +}; From 1529b92a5b212b55a7ca1f5b1e9b306adea8da2c Mon Sep 17 00:00:00 2001 From: vitalogy Date: Tue, 19 Jan 2016 07:28:17 +0100 Subject: [PATCH 2/3] rtc-ds1307.c: backport from linux-4.4 contains the following changes: * Convert to threaded IRQ with this, it is easier to drop the irq-handling for chips with no irq connected to the soc changes for threaded IRQ: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/rtc/rtc-ds1307.c?id=2fb07a10e0aa699ddb12aba1459208579bdc9802 * Fix kernel splat due to wakeup irq handling * Enable the mcp794xx alarm after programming time * Fix alarm programming for mcp794xx * Clean up ds1307_nvram_read and ds1307_nvram_write() * Sorting the headers NOTE: This is a backport from linux-4.4 to rpi-4.1.y, expect the irq handling, these are small changes --- drivers/rtc/rtc-ds1307.c | 113 ++++++++++++++------------------------- 1 file changed, 39 insertions(+), 74 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index c6789a737d606a..7c376d9d2a1966 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -11,14 +11,14 @@ * published by the Free Software Foundation. */ -#include +#include +#include #include +#include +#include +#include #include -#include #include -#include -#include -#include /* * We can't determine type by probing, but if we expect pre-Linux code @@ -114,7 +114,6 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; - struct work_struct work; s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, @@ -311,27 +310,17 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client, /*----------------------------------------------------------------------*/ /* - * The IRQ logic includes a "real" handler running in IRQ context just - * long enough to schedule this workqueue entry. We need a task context - * to talk to the RTC, since I2C I/O calls require that; and disable the - * IRQ until we clear its status on the chip, so that this handler can - * work with any type of triggering (not just falling edge). - * * The ds1337 and ds1339 both have two alarms, but we only use the first * one (with a "seconds" field). For ds1337 we expect nINTA is our alarm * signal; ds1339 chips have only one alarm signal. */ -static void ds1307_work(struct work_struct *work) +static irqreturn_t ds1307_irq(int irq, void *dev_id) { - struct ds1307 *ds1307; - struct i2c_client *client; - struct mutex *lock; + struct i2c_client *client = dev_id; + struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct mutex *lock = &ds1307->rtc->ops_lock; int stat, control; - ds1307 = container_of(work, struct ds1307, work); - client = ds1307->client; - lock = &ds1307->rtc->ops_lock; - mutex_lock(lock); stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); if (stat < 0) @@ -352,18 +341,8 @@ static void ds1307_work(struct work_struct *work) } out: - if (test_bit(HAS_ALARM, &ds1307->flags)) - enable_irq(client->irq); mutex_unlock(lock); -} -static irqreturn_t ds1307_irq(int irq, void *dev_id) -{ - struct i2c_client *client = dev_id; - struct ds1307 *ds1307 = i2c_get_clientdata(client); - - disable_irq_nosync(irq); - schedule_work(&ds1307->work); return IRQ_HANDLED; } @@ -634,13 +613,14 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { MCP794XX_BIT_ALMX_C1 | \ MCP794XX_BIT_ALMX_C2) -static void mcp794xx_work(struct work_struct *work) +static irqreturn_t mcp794xx_irq(int irq, void *dev_id) { - struct ds1307 *ds1307 = container_of(work, struct ds1307, work); - struct i2c_client *client = ds1307->client; + struct i2c_client *client = dev_id; + struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct mutex *lock = &ds1307->rtc->ops_lock; int reg, ret; - mutex_lock(&ds1307->rtc->ops_lock); + mutex_lock(lock); /* Check and clear alarm 0 interrupt flag. */ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL); @@ -665,9 +645,9 @@ static void mcp794xx_work(struct work_struct *work) rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); out: - if (test_bit(HAS_ALARM, &ds1307->flags)) - enable_irq(client->irq); - mutex_unlock(&ds1307->rtc->ops_lock); + mutex_unlock(lock); + + return IRQ_HANDLED; } static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) @@ -734,25 +714,25 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) regs[3] = bin2bcd(t->time.tm_sec); regs[4] = bin2bcd(t->time.tm_min); regs[5] = bin2bcd(t->time.tm_hour); - regs[6] = bin2bcd(t->time.tm_wday) + 1; + regs[6] = bin2bcd(t->time.tm_wday + 1); regs[7] = bin2bcd(t->time.tm_mday); - regs[8] = bin2bcd(t->time.tm_mon) + 1; + regs[8] = bin2bcd(t->time.tm_mon + 1); /* Clear the alarm 0 interrupt flag. */ regs[6] &= ~MCP794XX_BIT_ALMX_IF; /* Set alarm match: second, minute, hour, day, date, month. */ regs[6] |= MCP794XX_MSK_ALMX_MATCH; - - if (t->enabled) - regs[0] |= MCP794XX_BIT_ALM0_EN; - else - regs[0] &= ~MCP794XX_BIT_ALM0_EN; + /* Disable interrupt. We will not enable until completely programmed */ + regs[0] &= ~MCP794XX_BIT_ALM0_EN; ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs); if (ret < 0) return ret; - return 0; + if (!t->enabled) + return 0; + regs[0] |= MCP794XX_BIT_ALM0_EN; + return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, regs[0]); } static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -798,13 +778,6 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= ds1307->nvram->size)) - return 0; - if ((off + count) > ds1307->nvram->size) - count = ds1307->nvram->size - off; - if (unlikely(!count)) - return count; - result = ds1307->read_block_data(client, ds1307->nvram_offset + off, count, buf); if (result < 0) @@ -824,13 +797,6 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= ds1307->nvram->size)) - return -EFBIG; - if ((off + count) > ds1307->nvram->size) - count = ds1307->nvram->size - off; - if (unlikely(!count)) - return count; - result = ds1307->write_block_data(client, ds1307->nvram_offset + off, count, buf); if (result < 0) { @@ -896,6 +862,8 @@ static int ds1307_probe(struct i2c_client *client, bool want_irq = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); + irq_handler_t irq_handler = ds1307_irq; + static const int bbsqi_bitpos[] = { [ds_1337] = 0, [ds_1339] = DS1339_BIT_BBSQI, @@ -962,8 +930,6 @@ static int ds1307_probe(struct i2c_client *client, * running on Vbackup (BBSQI/BBSQW) */ if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, ds1307_work); - ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1053,7 +1019,7 @@ static int ds1307_probe(struct i2c_client *client, case mcp794xx: rtc_ops = &mcp794xx_rtc_ops; if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, mcp794xx_work); + irq_handler = mcp794xx_irq; want_irq = true; } break; @@ -1168,7 +1134,10 @@ static int ds1307_probe(struct i2c_client *client, bin2bcd(tmp)); } - device_set_wakeup_capable(&client->dev, want_irq); + if (want_irq) { + device_set_wakeup_capable(&client->dev, true); + set_bit(HAS_ALARM, &ds1307->flags); + } ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, rtc_ops, THIS_MODULE); if (IS_ERR(ds1307->rtc)) { @@ -1176,16 +1145,17 @@ static int ds1307_probe(struct i2c_client *client, } if (want_irq) { - err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, - ds1307->rtc->name, client); + err = devm_request_threaded_irq(&client->dev, + client->irq, NULL, irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + ds1307->rtc->name, client); if (err) { client->irq = 0; + device_set_wakeup_capable(&client->dev, false); + clear_bit(HAS_ALARM, &ds1307->flags); dev_err(&client->dev, "unable to request IRQ!\n"); - } else { - - set_bit(HAS_ALARM, &ds1307->flags); + } else dev_dbg(&client->dev, "got IRQ %d\n", client->irq); - } } if (chip->nvram_size) { @@ -1231,11 +1201,6 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); - if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) { - free_irq(client->irq, client); - cancel_work_sync(&ds1307->work); - } - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); From ba4b8980e0df95fb748d5d91ab07b86633bf0f62 Mon Sep 17 00:00:00 2001 From: vitalogy Date: Tue, 19 Jan 2016 08:06:07 +0100 Subject: [PATCH 3/3] rtc-ds1307.c: add DT property 'wakeup-source' to indicate the rtc can wakeup the device without an IRQ Tested with the Witty Pi extension board by UUGear that has an ds1337. --- drivers/rtc/rtc-ds1307.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 7c376d9d2a1966..850aaefea7a2dd 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -860,6 +860,7 @@ static int ds1307_probe(struct i2c_client *client, struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); bool want_irq = false; + bool ds1307_can_wakeup_device = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); irq_handler_t irq_handler = ds1307_irq; @@ -907,6 +908,20 @@ static int ds1307_probe(struct i2c_client *client, ds1307->write_block_data = ds1307_write_block_data; } +#ifdef CONFIG_OF +/* + * For devices with no IRQ directly connected to the SoC, the RTC chip + * can be forced as a wakeup source by stating that explicitly in + * the device's .dts file using the "wakeup-source" boolean property. + * If the "wakeup-source" property is set, don't request an IRQ. + * This will guarantee the 'wakealarm' sysfs entry is available on the device, + * if supported by the RTC. + */ + if (of_property_read_bool(client->dev.of_node, "wakeup-source")) { + ds1307_can_wakeup_device = true; + } +#endif + switch (ds1307->type) { case ds_1337: case ds_1339: @@ -925,11 +940,12 @@ static int ds1307_probe(struct i2c_client *client, ds1307->regs[0] &= ~DS1337_BIT_nEOSC; /* - * Using IRQ? Disable the square wave and both alarms. + * Using IRQ or defined as wakeup-source? + * Disable the square wave and both alarms. * For some variants, be sure alarms can trigger when we're * running on Vbackup (BBSQI/BBSQW) */ - if (ds1307->client->irq > 0 && chip->alarm) { + if (chip->alarm && (ds1307->client->irq > 0 || ds1307_can_wakeup_device)) { ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1144,6 +1160,14 @@ static int ds1307_probe(struct i2c_client *client, return PTR_ERR(ds1307->rtc); } + if (ds1307_can_wakeup_device) { + /* Disable request for an IRQ */ + want_irq = false; + dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n"); + /* We cannot support UIE mode if we do not have an IRQ line */ + ds1307->rtc->uie_unsupported = 1; + } + if (want_irq) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler,