On the AM335x SoC rev. <= 1.0 the "Input Function of the EXTINTn
Terminal is Inverted", for which the only remedy is to "Use an active
high interrupt source or use an external inverter to change the
polarity of any active low interrupt source."
This pin is used as IRQ pin for the LTC3589 PMIC on the Ka-Ro
electronics TX48 module. Make the IRQ optional in the driver and use a
polling routine instead if no IRQ is specified in DT.
Otherwise the driver will continuously generate interrupts and make
the system unusable.
#define LTC3589_VCCR_SW3_GO BIT(4)
#define LTC3589_VCCR_LDO2_GO BIT(6)
#define LTC3589_VCCR_SW3_GO BIT(4)
#define LTC3589_VCCR_LDO2_GO BIT(6)
+#define POLL_PERIOD 1000
+
enum ltc3589_variant {
LTC3589,
LTC3589_1,
enum ltc3589_variant {
LTC3589,
LTC3589_1,
enum ltc3589_variant variant;
struct ltc3589_regulator regulator_descs[LTC3589_NUM_REGULATORS];
struct regulator_dev *regulators[LTC3589_NUM_REGULATORS];
enum ltc3589_variant variant;
struct ltc3589_regulator regulator_descs[LTC3589_NUM_REGULATORS];
struct regulator_dev *regulators[LTC3589_NUM_REGULATORS];
+ struct delayed_work poll_timer;
};
static const int ltc3589_ldo4[] = {
};
static const int ltc3589_ldo4[] = {
.cache_type = REGCACHE_RBTREE,
};
.cache_type = REGCACHE_RBTREE,
};
-
-static irqreturn_t ltc3589_isr(int irq, void *dev_id)
+static inline void ltc3589_handle_irq(struct ltc3589 *ltc3589)
- struct ltc3589 *ltc3589 = dev_id;
- unsigned int i, irqstat, event;
+ u32 irqstat, event;
+ int i;
regmap_read(ltc3589->regmap, LTC3589_IRQSTAT, &irqstat);
regmap_read(ltc3589->regmap, LTC3589_IRQSTAT, &irqstat);
/* Clear warning condition */
regmap_write(ltc3589->regmap, LTC3589_CLIRQ, 0);
/* Clear warning condition */
regmap_write(ltc3589->regmap, LTC3589_CLIRQ, 0);
+}
+
+static void ltc3589_poll_func(struct work_struct *work)
+{
+ struct ltc3589 *ltc3589 = container_of(work, struct ltc3589,
+ poll_timer.work);
+ unsigned long timeout = msecs_to_jiffies(POLL_PERIOD);
+
+ ltc3589_handle_irq(ltc3589);
+
+ schedule_delayed_work(<c3589->poll_timer, timeout);
+}
+
+static irqreturn_t ltc3589_isr(int irq, void *dev_id)
+{
+ struct ltc3589 *ltc3589 = dev_id;
+
+ ltc3589_handle_irq(ltc3589);
+ if (client->irq <= 0) {
+ dev_warn(dev,
+ "No interrupt configured; poll for thermal shutdown and undervoltage events\n");
+
+ INIT_DELAYED_WORK(<c3589->poll_timer, ltc3589_poll_func);
+ schedule_delayed_work(<c3589->poll_timer,
+ msecs_to_jiffies(POLL_PERIOD));
+
+ return 0;
+ }
ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+static int ltc3589_remove(struct i2c_client *client)
+{
+ struct ltc3589 *ltc3589 = i2c_get_clientdata(client);
+
+ if (client->irq <= 0)
+ cancel_delayed_work(<c3589->poll_timer);
+
+ return 0;
+}
+
static struct i2c_device_id ltc3589_i2c_id[] = {
{ "ltc3589", LTC3589 },
{ "ltc3589-1", LTC3589_1 },
static struct i2c_device_id ltc3589_i2c_id[] = {
{ "ltc3589", LTC3589 },
{ "ltc3589-1", LTC3589_1 },
.owner = THIS_MODULE,
},
.probe = ltc3589_probe,
.owner = THIS_MODULE,
},
.probe = ltc3589_probe,
+ .remove = ltc3589_remove,
.id_table = ltc3589_i2c_id,
};
module_i2c_driver(ltc3589_driver);
.id_table = ltc3589_i2c_id,
};
module_i2c_driver(ltc3589_driver);