static int rt5025_gpio_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data; struct rt5025_gpio_info *gi; bool use_dt = pdev->dev.of_node; int rc = 0; gi = devm_kzalloc(&pdev->dev, sizeof(*gi), GFP_KERNEL); if (!gi) return -ENOMEM; gi->i2c = chip->i2c; if (use_dt) { rt_parse_dt(gi, &pdev->dev); } else { if (!pdata) { rc = -EINVAL; goto out_dev; } pdev->dev.platform_data = pdata->gpio_pdata; rt_parse_pdata(gi, &pdev->dev); } gi->gpio_chip.direction_input = rt5025_gpio_direction_input; gi->gpio_chip.direction_output = rt5025_gpio_direction_output; gi->gpio_chip.get = rt5025_gpio_get_value; gi->gpio_chip.set = rt5025_gpio_set_value; gi->gpio_chip.can_sleep = 0; gi->gpio_chip.base = -1; gi->gpio_chip.ngpio = gi->ngpio; gi->gpio_chip.label = pdev->name; gi->gpio_chip.dev = &pdev->dev; gi->gpio_chip.owner = THIS_MODULE; rc = gpiochip_add(&gi->gpio_chip); if (rc) goto out_dev; platform_set_drvdata(pdev, gi); dev_info(&pdev->dev, "driver successfully loaded\n"); return rc; out_dev: return rc; }
static int rt5025_misc_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data; struct rt5025_misc_info *mi; bool use_dt = pdev->dev.of_node; int ret = 0; mi = devm_kzalloc(&pdev->dev, sizeof(*mi), GFP_KERNEL); if (!mi) return -ENOMEM; mi->i2c = chip->i2c; mi->dev = &pdev->dev; if (use_dt) { rt_parse_dt(mi, &pdev->dev); } else { if (!pdata) { dev_err(&pdev->dev, "no initial platform data\n"); ret = -EINVAL; goto err_init; } pdev->dev.platform_data = pdata->misc_pdata; rt_parse_pdata(mi, &pdev->dev); } /*for shutdown control*/ g_shdn = chip->i2c; if (rt_pm_off && !pm_power_off) pm_power_off = rt5025_power_off; platform_set_drvdata(pdev, mi); chip->misc_info = mi; dev_info(&pdev->dev, "driver successfully loaded\n"); return 0; err_init: return ret; }
static inline struct regulator_dev* rt5746_regulator_register( struct regulator_desc *regulator_desc, struct device *dev, struct regulator_init_data *init_data, void *driver_data) { #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) struct regulator_config config = { .dev = dev, .init_data = init_data, .driver_data = driver_data, .of_node = dev->of_node, }; return regulator_register(®ulator_desc, &config); #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(3,0,0)) return regulator_register(regulator_desc,dev,init_data, driver_data,dev->of_node); #else return regulator_register(regulator_desc,dev,init_data,driver_data); #endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) */ } static irqreturn_t rt5746_irq_handler(int irqno, void *param) { struct rt5746_regulator_info *ri = param; int regval; int i; if (ri->suspend) { schedule_delayed_work(&ri->irq_dwork, msecs_to_jiffies(50)); goto fin_intr; } regval = rt5746_reg_read(ri->i2c, RT5746_REG_INTACK); if (regval<0) dev_err(ri->dev, "read irq event io fail\n"); else { if (regval == 0) goto fin_intr; regval &= (~rt5746_init_regval[0]); for (i=0; i<RT5746_IRQ_MAX; i++) { if (regval&(1<<i)) { switch (i) { case RT5746_IRQ_PGOOD: dev_err(ri->dev, "pgood event occur\n"); break; case RT5746_IRQ_IDCDC: dev_err(ri->dev, "dcdc over current\n"); break; case RT5746_IRQ_UVLO: dev_err(ri->dev, "uvlo event occur\n"); break; case RT5746_IRQ_TPREW: dev_info(ri->dev, "thermal pre-warning\n"); break; case RT5746_IRQ_TWARN: dev_warn(ri->dev, "thermal warning\n"); break; case RT5746_IRQ_TSD: dev_err(ri->dev, "thermal shutdown\n"); break; default: dev_err(ri->dev, "unrecognized event\n"); break; } } } } fin_intr: return IRQ_HANDLED; } static void rt5746_irq_dwork_func(struct work_struct *work) { struct rt5746_regulator_info *ri = container_of(work, struct rt5746_regulator_info, irq_dwork.work); rt5746_irq_handler(0, ri); } static void rt5746_interrupt_init(struct rt5746_regulator_info *ri) { struct rt5746_platform_data *pdata = ri->dev->platform_data; int rc = (int)0, irq_no = (int)0; if (gpio_is_valid(pdata->irq_gpio)) { rc = gpio_request(pdata->irq_gpio, "rt5746_irq_gpio"); if (rc<0) { dev_err(ri->dev, "gpio request failed\n"); return; } gpio_direction_input(pdata->irq_gpio); irq_no = gpio_to_irq(pdata->irq_gpio); if (irq_no<0) { dev_err(ri->dev, "gpio to irq fail\n"); gpio_free(pdata->irq_gpio); return; } if (devm_request_threaded_irq(ri->dev, irq_no, NULL, rt5746_irq_handler, IRQF_TRIGGER_FALLING|IRQF_NO_SUSPEND|IRQF_DISABLED, "rt5746_irq", ri)) { dev_err(ri->dev, "request irq fail\n"); gpio_free(pdata->irq_gpio); return; } enable_irq_wake(irq_no); schedule_delayed_work(&ri->irq_dwork, msecs_to_jiffies(100)); } else dev_info(ri->dev, "gpio is not valid\n"); } static void rt_parse_dt(struct device *dev) { #ifdef CONFIG_OF struct regulator_init_data *init_data = NULL; struct rt5746_platform_data *pdata = dev->platform_data; struct device_node *np = dev->of_node; int rc; u32 tmp; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) init_data = of_get_regulator_init_data(dev, dev->of_node); #else init_data = of_get_regulator_init_data(dev); #endif /* #if (LINUX_KERNEL_VERSION >= KERNEL_VERSION(3,3,0)) */ pdata->regulator = init_data; rc = of_property_read_u32(np, "rt,standby_uV", &tmp); if (rc<0) dev_info(dev, "no standby voltage setting, use ic default\n"); else pdata->standby_uV = tmp; rc = of_property_read_u32(np, "rt,rampup_sel", &tmp); if (rc) dev_info(dev, "no rampup_sel property, use ic default value\n"); else { if (tmp>RT5746_RAMPUP_MAX) tmp = RT5746_RAMPUP_MAX; pdata->rampup_sel = tmp; } rc = of_property_read_u32(np, "rt,rampdn_sel", &tmp); if (rc) dev_info(dev, "no rampdn_sel property, use ic default value\n"); else { if (tmp>RT5746_RAMPDN_MAX) tmp = RT5746_RAMPDN_MAX; pdata->rampdn_sel = tmp; } rc = of_property_read_u32(np, "rt,ipeak_sel", &tmp); if (rc) dev_info(dev, "no ipeak_sel property, use ic default value\n"); else { if (tmp>RT5746_IPEAK_MAX) tmp = RT5746_IPEAK_MAX; pdata->ipeak_sel = tmp; } rc = of_property_read_u32(np, "rt,tpwth_sel", &tmp); if (rc) dev_info(dev, "no tpwth_sel property, use ic default value\n"); else { if (tmp>RT5746_TPWTH_MAX) tmp = RT5746_TPWTH_MAX; pdata->tpwth_sel = tmp; } if (of_property_read_bool(np, "rt,rearm_en")) pdata->rearm_en = 1; if (of_property_read_bool(np, "rt,discharge_en")) pdata->discharge_en = 1; pdata->irq_gpio = of_get_named_gpio(np, "rt,irq_gpio", 0); #endif /* #ifdef CONFIG_OF */ } static int rt5746_regulator_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct rt5746_regulator_info *ri; struct rt5746_platform_data *pdata = i2c->dev.platform_data; struct regulator_dev *rdev; struct regulator_init_data *init_data; bool use_dt = i2c->dev.of_node; int val = 0; int ret = 0; ri = &rt5746_regulator_info; if (use_dt) { pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { ret = -ENOMEM; goto err_init; } i2c->dev.platform_data = pdata; rt_parse_dt(&i2c->dev); } else { if (!pdata) { ret = -EINVAL; goto err_init; } } init_data = pdata->regulator; if (!init_data) { dev_err(&i2c->dev, "no initializing data\n"); ret = -EINVAL; goto err_init; } mutex_init(&ri->io_lock); INIT_DELAYED_WORK(&ri->irq_dwork, rt5746_irq_dwork_func); ri->i2c = i2c; ri->dev = &i2c->dev; i2c_set_clientdata(i2c, ri); //check ic communication & ic vendor id val = rt5746_reg_read(i2c, RT5746_REG_VID); if (val<0) { ret = -EIO; goto err_init; } else { dev_info(&i2c->dev, "vendor id = %02x\n", val); if (val!=RT5746_VEN_ID) { ret = -EINVAL; goto err_init; } } rt5746_parse_initconfig(pdata); rt5746_register_init(i2c); //interrupt gpio init if (pdata->irq_gpio<0) dev_info(&i2c->dev, "no interrupt irq specified\n"); else rt5746_interrupt_init(ri); rdev = rt5746_regulator_register(&ri->desc, &i2c->dev, init_data, ri); if (IS_ERR(rdev)) { dev_err(&i2c->dev, "failed to register regulator %s\n", ri->desc.name); return PTR_ERR(rdev); } ri->rdev = rdev; //set suspend voltage if (pdata->standby_uV>0) rt5746_set_suspend_voltage(rdev, pdata->standby_uV); rt_dbg_create_attrs(&i2c->dev); dev_info(&i2c->dev, "regulator successfully registered\n"); err_init: return ret; } static int rt5746_regulator_remove(struct i2c_client *i2c) { struct rt5746_regulator_info *ri = i2c_get_clientdata(i2c); regulator_unregister(ri->rdev); dev_info(&i2c->dev, "regulator driver removed\n"); return 0; } static int rt5746_regulator_suspend(struct i2c_client *i2c, pm_message_t mesg) { struct rt5746_regulator_info *ri = i2c_get_clientdata(i2c); ri->suspend = 1; return 0; } static int rt5746_regulator_resume(struct i2c_client *i2c) { struct rt5746_regulator_info *ri = i2c_get_clientdata(i2c); ri->suspend = 0; return 0; } static const struct of_device_id rt_match_table[] = { { .compatible = "richtek,rt5746",}, {}, };