static int dw_i2c_probe(struct platform_device *pdev) { struct dw_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem; struct dw_i2c_platform_data *pdata; int irq, r; u32 clk_freq, ht = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); if (!dev) return -ENOMEM; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) return PTR_ERR(dev->base); init_completion(&dev->cmd_complete); mutex_init(&dev->lock); dev->dev = &pdev->dev; dev->irq = irq; platform_set_drvdata(pdev, dev); /* fast mode by default because of legacy reasons */ clk_freq = 400000; if (has_acpi_companion(&pdev->dev)) { dw_i2c_acpi_configure(pdev); } else if (pdev->dev.of_node) { of_property_read_u32(pdev->dev.of_node, "i2c-sda-hold-time-ns", &ht); of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns", &dev->sda_falling_time); of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns", &dev->scl_falling_time); of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clk_freq); /* Only standard mode at 100kHz and fast mode at 400kHz * are supported. */ if (clk_freq != 100000 && clk_freq != 400000) { dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); return -EINVAL; } } else { pdata = dev_get_platdata(&pdev->dev); if (pdata) clk_freq = pdata->i2c_scl_freq; } r = i2c_dw_eval_lock_support(dev); if (r) return r; dev->functionality = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK; if (clk_freq == 100000) dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_STD; else dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; dev->clk = devm_clk_get(&pdev->dev, NULL); dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); clk_prepare_enable(dev->clk); if (!dev->sda_hold_time && ht) { u32 ic_clk = dev->get_clk_rate_khz(dev); dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000, 1000000); } if (!dev->tx_fifo_depth) { u32 param1 = i2c_dw_read_comp_param(dev); dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; dev->adapter.nr = pdev->id; }
struct dw_i2c_dev *i2c_dw_setup(struct device *pdev, int bus_idx, unsigned long start, unsigned long len, int irq) { struct dw_i2c_dev *dev; struct i2c_adapter *adap; void __iomem *base; struct dw_controller *controller; int r; #ifdef CONFIG_ACPI void *handle_save = ACPI_HANDLE(pdev); #endif u32 param1; if (bus_idx >= ARRAY_SIZE(dw_controllers)) { dev_err(pdev, "invalid bus index %d\n", bus_idx); r = -EINVAL; goto exit; } controller = &dw_controllers[bus_idx]; base = ioremap_nocache(start, len); if (!base) { dev_err(pdev, "I/O memory remapping failed\n"); r = -ENOMEM; goto exit; } dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); if (!dev) { r = -ENOMEM; goto err_iounmap; } init_completion(&dev->cmd_complete); sema_init(&dev->lock, 1); dev->status = STATUS_IDLE; dev->clk = NULL; dev->controller = controller; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; dev->base = base; dev->dev = get_device(pdev); dev->functionality = I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK; dev->master_cfg = controller->bus_cfg; dev->get_scl_cfg = controller->scl_cfg; dev->enable_stop = controller->enable_stop; dev->clk_khz = controller->clk_khz; dev->speed_cfg = dev->master_cfg & DW_IC_SPEED_MASK; dev->use_dyn_clk = 0; dev->reset = controller->reset; dev->irq = irq; dev->share_irq = controller->share_irq; dev->abort = intel_mid_dw_i2c_abort; dev->tx_fifo_depth = controller->tx_fifo_depth; dev->rx_fifo_depth = controller->rx_fifo_depth; dev->fast_plus = controller->fast_plus; dev_set_drvdata(pdev, dev); dw_i2c_acpi_setup(pdev, dev); if (!dev->tx_fifo_depth || !dev->rx_fifo_depth) { param1 = i2c_dw_read_comp_param(dev); dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; }