0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/extcon-provider.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/mfd/intel_soc_pmic.h>
0012 #include <linux/mfd/intel_soc_pmic_mrfld.h>
0013 #include <linux/mod_devicetable.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regmap.h>
0017
0018 #include "extcon-intel.h"
0019
0020 #define BCOVE_USBIDCTRL 0x19
0021 #define BCOVE_USBIDCTRL_ID BIT(0)
0022 #define BCOVE_USBIDCTRL_ACA BIT(1)
0023 #define BCOVE_USBIDCTRL_ALL (BCOVE_USBIDCTRL_ID | BCOVE_USBIDCTRL_ACA)
0024
0025 #define BCOVE_USBIDSTS 0x1a
0026 #define BCOVE_USBIDSTS_GND BIT(0)
0027 #define BCOVE_USBIDSTS_RARBRC_MASK GENMASK(2, 1)
0028 #define BCOVE_USBIDSTS_RARBRC_SHIFT 1
0029 #define BCOVE_USBIDSTS_NO_ACA 0
0030 #define BCOVE_USBIDSTS_R_ID_A 1
0031 #define BCOVE_USBIDSTS_R_ID_B 2
0032 #define BCOVE_USBIDSTS_R_ID_C 3
0033 #define BCOVE_USBIDSTS_FLOAT BIT(3)
0034 #define BCOVE_USBIDSTS_SHORT BIT(4)
0035
0036 #define BCOVE_CHGRIRQ_ALL (BCOVE_CHGRIRQ_VBUSDET | BCOVE_CHGRIRQ_DCDET | \
0037 BCOVE_CHGRIRQ_BATTDET | BCOVE_CHGRIRQ_USBIDDET)
0038
0039 #define BCOVE_CHGRCTRL0 0x4b
0040 #define BCOVE_CHGRCTRL0_CHGRRESET BIT(0)
0041 #define BCOVE_CHGRCTRL0_EMRGCHREN BIT(1)
0042 #define BCOVE_CHGRCTRL0_EXTCHRDIS BIT(2)
0043 #define BCOVE_CHGRCTRL0_SWCONTROL BIT(3)
0044 #define BCOVE_CHGRCTRL0_TTLCK BIT(4)
0045 #define BCOVE_CHGRCTRL0_BIT_5 BIT(5)
0046 #define BCOVE_CHGRCTRL0_BIT_6 BIT(6)
0047 #define BCOVE_CHGRCTRL0_CHR_WDT_NOKICK BIT(7)
0048
0049 struct mrfld_extcon_data {
0050 struct device *dev;
0051 struct regmap *regmap;
0052 struct extcon_dev *edev;
0053 unsigned int status;
0054 unsigned int id;
0055 };
0056
0057 static const unsigned int mrfld_extcon_cable[] = {
0058 EXTCON_USB,
0059 EXTCON_USB_HOST,
0060 EXTCON_CHG_USB_SDP,
0061 EXTCON_CHG_USB_CDP,
0062 EXTCON_CHG_USB_DCP,
0063 EXTCON_CHG_USB_ACA,
0064 EXTCON_NONE,
0065 };
0066
0067 static int mrfld_extcon_clear(struct mrfld_extcon_data *data, unsigned int reg,
0068 unsigned int mask)
0069 {
0070 return regmap_update_bits(data->regmap, reg, mask, 0x00);
0071 }
0072
0073 static int mrfld_extcon_set(struct mrfld_extcon_data *data, unsigned int reg,
0074 unsigned int mask)
0075 {
0076 return regmap_update_bits(data->regmap, reg, mask, 0xff);
0077 }
0078
0079 static int mrfld_extcon_sw_control(struct mrfld_extcon_data *data, bool enable)
0080 {
0081 unsigned int mask = BCOVE_CHGRCTRL0_SWCONTROL;
0082 struct device *dev = data->dev;
0083 int ret;
0084
0085 if (enable)
0086 ret = mrfld_extcon_set(data, BCOVE_CHGRCTRL0, mask);
0087 else
0088 ret = mrfld_extcon_clear(data, BCOVE_CHGRCTRL0, mask);
0089 if (ret)
0090 dev_err(dev, "can't set SW control: %d\n", ret);
0091 return ret;
0092 }
0093
0094 static int mrfld_extcon_get_id(struct mrfld_extcon_data *data)
0095 {
0096 struct regmap *regmap = data->regmap;
0097 unsigned int id;
0098 bool ground;
0099 int ret;
0100
0101 ret = regmap_read(regmap, BCOVE_USBIDSTS, &id);
0102 if (ret)
0103 return ret;
0104
0105 if (id & BCOVE_USBIDSTS_FLOAT)
0106 return INTEL_USB_ID_FLOAT;
0107
0108 switch ((id & BCOVE_USBIDSTS_RARBRC_MASK) >> BCOVE_USBIDSTS_RARBRC_SHIFT) {
0109 case BCOVE_USBIDSTS_R_ID_A:
0110 return INTEL_USB_RID_A;
0111 case BCOVE_USBIDSTS_R_ID_B:
0112 return INTEL_USB_RID_B;
0113 case BCOVE_USBIDSTS_R_ID_C:
0114 return INTEL_USB_RID_C;
0115 }
0116
0117
0118
0119
0120
0121
0122 ground = id & BCOVE_USBIDSTS_GND;
0123 switch ('A' + BCOVE_MAJOR(data->id)) {
0124 case 'A':
0125 return ground ? INTEL_USB_ID_GND : INTEL_USB_ID_FLOAT;
0126 case 'B':
0127 return ground ? INTEL_USB_ID_FLOAT : INTEL_USB_ID_GND;
0128 }
0129
0130
0131 return INTEL_USB_ID_FLOAT;
0132 }
0133
0134 static int mrfld_extcon_role_detect(struct mrfld_extcon_data *data)
0135 {
0136 unsigned int id;
0137 bool usb_host;
0138 int ret;
0139
0140 ret = mrfld_extcon_get_id(data);
0141 if (ret < 0)
0142 return ret;
0143
0144 id = ret;
0145
0146 usb_host = (id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A);
0147 extcon_set_state_sync(data->edev, EXTCON_USB_HOST, usb_host);
0148
0149 return 0;
0150 }
0151
0152 static int mrfld_extcon_cable_detect(struct mrfld_extcon_data *data)
0153 {
0154 struct regmap *regmap = data->regmap;
0155 unsigned int status, change;
0156 int ret;
0157
0158
0159
0160
0161
0162
0163 ret = regmap_read(regmap, BCOVE_SCHGRIRQ1, &status);
0164 if (ret)
0165 return ret;
0166
0167 change = status ^ data->status;
0168 if (!change)
0169 return -ENODATA;
0170
0171 if (change & BCOVE_CHGRIRQ_USBIDDET) {
0172 ret = mrfld_extcon_role_detect(data);
0173 if (ret)
0174 return ret;
0175 }
0176
0177 data->status = status;
0178
0179 return 0;
0180 }
0181
0182 static irqreturn_t mrfld_extcon_interrupt(int irq, void *dev_id)
0183 {
0184 struct mrfld_extcon_data *data = dev_id;
0185 int ret;
0186
0187 ret = mrfld_extcon_cable_detect(data);
0188
0189 mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR);
0190
0191 return ret ? IRQ_NONE: IRQ_HANDLED;
0192 }
0193
0194 static int mrfld_extcon_probe(struct platform_device *pdev)
0195 {
0196 struct device *dev = &pdev->dev;
0197 struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
0198 struct regmap *regmap = pmic->regmap;
0199 struct mrfld_extcon_data *data;
0200 unsigned int status;
0201 unsigned int id;
0202 int irq, ret;
0203
0204 irq = platform_get_irq(pdev, 0);
0205 if (irq < 0)
0206 return irq;
0207
0208 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0209 if (!data)
0210 return -ENOMEM;
0211
0212 data->dev = dev;
0213 data->regmap = regmap;
0214
0215 data->edev = devm_extcon_dev_allocate(dev, mrfld_extcon_cable);
0216 if (IS_ERR(data->edev))
0217 return -ENOMEM;
0218
0219 ret = devm_extcon_dev_register(dev, data->edev);
0220 if (ret < 0) {
0221 dev_err(dev, "can't register extcon device: %d\n", ret);
0222 return ret;
0223 }
0224
0225 ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_extcon_interrupt,
0226 IRQF_ONESHOT | IRQF_SHARED, pdev->name,
0227 data);
0228 if (ret) {
0229 dev_err(dev, "can't register IRQ handler: %d\n", ret);
0230 return ret;
0231 }
0232
0233 ret = regmap_read(regmap, BCOVE_ID, &id);
0234 if (ret) {
0235 dev_err(dev, "can't read PMIC ID: %d\n", ret);
0236 return ret;
0237 }
0238
0239 data->id = id;
0240
0241 ret = mrfld_extcon_sw_control(data, true);
0242 if (ret)
0243 return ret;
0244
0245
0246 mrfld_extcon_role_detect(data);
0247
0248
0249
0250
0251
0252
0253 regmap_read(regmap, BCOVE_SCHGRIRQ1, &status);
0254 data->status = status;
0255
0256 mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR);
0257 mrfld_extcon_clear(data, BCOVE_MCHGRIRQ1, BCOVE_CHGRIRQ_ALL);
0258
0259 mrfld_extcon_set(data, BCOVE_USBIDCTRL, BCOVE_USBIDCTRL_ALL);
0260
0261 platform_set_drvdata(pdev, data);
0262
0263 return 0;
0264 }
0265
0266 static int mrfld_extcon_remove(struct platform_device *pdev)
0267 {
0268 struct mrfld_extcon_data *data = platform_get_drvdata(pdev);
0269
0270 mrfld_extcon_sw_control(data, false);
0271
0272 return 0;
0273 }
0274
0275 static const struct platform_device_id mrfld_extcon_id_table[] = {
0276 { .name = "mrfld_bcove_pwrsrc" },
0277 {}
0278 };
0279 MODULE_DEVICE_TABLE(platform, mrfld_extcon_id_table);
0280
0281 static struct platform_driver mrfld_extcon_driver = {
0282 .driver = {
0283 .name = "mrfld_bcove_pwrsrc",
0284 },
0285 .probe = mrfld_extcon_probe,
0286 .remove = mrfld_extcon_remove,
0287 .id_table = mrfld_extcon_id_table,
0288 };
0289 module_platform_driver(mrfld_extcon_driver);
0290
0291 MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
0292 MODULE_DESCRIPTION("extcon driver for Intel Merrifield Basin Cove PMIC");
0293 MODULE_LICENSE("GPL v2");