aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon/extcon-arizona.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-01 17:03:06 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-02 06:53:51 -0400
commit6fed4d869a11fdbb4c6a5e444dfb2c22f92c3e46 (patch)
tree53c3e4ec22ae7a35c0a209ba4c2300b8743a07cd /drivers/extcon/extcon-arizona.c
parent84eaa13616b6e7d001b7f7b909228087779b677b (diff)
extcon: arizona: Allow configuration of button detection
The Arizona button detection circuit is configurable, allowing the system integrator to program a range of thresholds for the buttons supported on the accessory but currently the driver uses the default button ranges and does not provide any flexibility in how this is exposed to the application layer. Provide platform data allowing the user to control this and to map the buttons to keys in the input subsystem. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/extcon/extcon-arizona.c')
-rw-r--r--drivers/extcon/extcon-arizona.c164
1 files changed, 125 insertions, 39 deletions
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 4bb0e9ae405d..e2339629126a 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -33,7 +33,7 @@
33#include <linux/mfd/arizona/pdata.h> 33#include <linux/mfd/arizona/pdata.h>
34#include <linux/mfd/arizona/registers.h> 34#include <linux/mfd/arizona/registers.h>
35 35
36#define ARIZONA_NUM_BUTTONS 6 36#define ARIZONA_MAX_MICD_RANGE 8
37 37
38#define ARIZONA_ACCDET_MODE_MIC 0 38#define ARIZONA_ACCDET_MODE_MIC 0
39#define ARIZONA_ACCDET_MODE_HPL 1 39#define ARIZONA_ACCDET_MODE_HPL 1
@@ -50,6 +50,9 @@ struct arizona_extcon_info {
50 const struct arizona_micd_config *micd_modes; 50 const struct arizona_micd_config *micd_modes;
51 int micd_num_modes; 51 int micd_num_modes;
52 52
53 const struct arizona_micd_range *micd_ranges;
54 int num_micd_ranges;
55
53 bool micd_reva; 56 bool micd_reva;
54 bool micd_clamp; 57 bool micd_clamp;
55 58
@@ -71,20 +74,25 @@ struct arizona_extcon_info {
71}; 74};
72 75
73static const struct arizona_micd_config micd_default_modes[] = { 76static const struct arizona_micd_config micd_default_modes[] = {
74 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
75 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, 77 { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
78 { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
76}; 79};
77 80
78static struct { 81static const struct arizona_micd_range micd_default_ranges[] = {
79 u16 status; 82 { .max = 11, .key = BTN_0 },
80 int report; 83 { .max = 28, .key = BTN_1 },
81} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = { 84 { .max = 54, .key = BTN_2 },
82 { 0x1, BTN_0 }, 85 { .max = 100, .key = BTN_3 },
83 { 0x2, BTN_1 }, 86 { .max = 186, .key = BTN_4 },
84 { 0x4, BTN_2 }, 87 { .max = 430, .key = BTN_5 },
85 { 0x8, BTN_3 }, 88};
86 { 0x10, BTN_4 }, 89
87 { 0x20, BTN_5 }, 90static const int arizona_micd_levels[] = {
91 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
92 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
93 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
94 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
95 1257,
88}; 96};
89 97
90#define ARIZONA_CABLE_MECHANICAL 0 98#define ARIZONA_CABLE_MECHANICAL 0
@@ -153,7 +161,7 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
153{ 161{
154 struct arizona *arizona = info->arizona; 162 struct arizona *arizona = info->arizona;
155 163
156 mode %= info->num_micd_modes; 164 mode %= info->micd_num_modes;
157 165
158 if (arizona->pdata.micd_pol_gpio > 0) 166 if (arizona->pdata.micd_pol_gpio > 0)
159 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, 167 gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
@@ -728,7 +736,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
728 struct arizona_extcon_info *info = data; 736 struct arizona_extcon_info *info = data;
729 struct arizona *arizona = info->arizona; 737 struct arizona *arizona = info->arizona;
730 unsigned int val, lvl; 738 unsigned int val, lvl;
731 int ret, i; 739 int ret, i, key;
732 740
733 mutex_lock(&info->lock); 741 mutex_lock(&info->lock);
734 742
@@ -815,12 +823,13 @@ static irqreturn_t arizona_micdet(int irq, void *data)
815 lvl = val & ARIZONA_MICD_LVL_MASK; 823 lvl = val & ARIZONA_MICD_LVL_MASK;
816 lvl >>= ARIZONA_MICD_LVL_SHIFT; 824 lvl >>= ARIZONA_MICD_LVL_SHIFT;
817 825
818 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) 826 WARN_ON(!lvl);
819 if (lvl & arizona_lvl_to_key[i].status) 827 WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
820 input_report_key(info->input, 828 if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
821 arizona_lvl_to_key[i].report, 829 key = info->micd_ranges[ffs(lvl) - 1].key;
822 1); 830 input_report_key(info->input, key, 1);
823 input_sync(info->input); 831 input_sync(info->input);
832 }
824 833
825 } else if (info->detecting) { 834 } else if (info->detecting) {
826 dev_dbg(arizona->dev, "Headphone detected\n"); 835 dev_dbg(arizona->dev, "Headphone detected\n");
@@ -834,9 +843,9 @@ static irqreturn_t arizona_micdet(int irq, void *data)
834 } 843 }
835 } else { 844 } else {
836 dev_dbg(arizona->dev, "Mic button released\n"); 845 dev_dbg(arizona->dev, "Mic button released\n");
837 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) 846 for (i = 0; i < info->num_micd_ranges; i++)
838 input_report_key(info->input, 847 input_report_key(info->input,
839 arizona_lvl_to_key[i].report, 0); 848 info->micd_ranges[i].key, 0);
840 input_sync(info->input); 849 input_sync(info->input);
841 arizona_extcon_pulse_micbias(info); 850 arizona_extcon_pulse_micbias(info);
842 } 851 }
@@ -923,9 +932,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
923 info->mic = false; 932 info->mic = false;
924 info->hpdet_done = false; 933 info->hpdet_done = false;
925 934
926 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) 935 for (i = 0; i < info->num_micd_ranges; i++)
927 input_report_key(info->input, 936 input_report_key(info->input,
928 arizona_lvl_to_key[i].report, 0); 937 info->micd_ranges[i].key, 0);
929 input_sync(info->input); 938 input_sync(info->input);
930 939
931 ret = extcon_update_state(&info->edev, 0xffffffff, 0); 940 ret = extcon_update_state(&info->edev, 0xffffffff, 0);
@@ -954,13 +963,33 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
954 return IRQ_HANDLED; 963 return IRQ_HANDLED;
955} 964}
956 965
966/* Map a level onto a slot in the register bank */
967static void arizona_micd_set_level(struct arizona *arizona, int index,
968 unsigned int level)
969{
970 int reg;
971 unsigned int mask;
972
973 reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
974
975 if (!(index % 2)) {
976 mask = 0x3f00;
977 level <<= 8;
978 } else {
979 mask = 0x3f;
980 }
981
982 /* Program the level itself */
983 regmap_update_bits(arizona->regmap, reg, mask, level);
984}
985
957static int arizona_extcon_probe(struct platform_device *pdev) 986static int arizona_extcon_probe(struct platform_device *pdev)
958{ 987{
959 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); 988 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
960 struct arizona_pdata *pdata; 989 struct arizona_pdata *pdata;
961 struct arizona_extcon_info *info; 990 struct arizona_extcon_info *info;
962 int jack_irq_fall, jack_irq_rise; 991 int jack_irq_fall, jack_irq_rise;
963 int ret, mode, i; 992 int ret, mode, i, j;
964 993
965 if (!arizona->dapm || !arizona->dapm->card) 994 if (!arizona->dapm || !arizona->dapm->card)
966 return -EPROBE_DEFER; 995 return -EPROBE_DEFER;
@@ -1013,6 +1042,17 @@ static int arizona_extcon_probe(struct platform_device *pdev)
1013 goto err; 1042 goto err;
1014 } 1043 }
1015 1044
1045 info->input = devm_input_allocate_device(&pdev->dev);
1046 if (!info->input) {
1047 dev_err(arizona->dev, "Can't allocate input dev\n");
1048 ret = -ENOMEM;
1049 goto err_register;
1050 }
1051
1052 info->input->name = "Headset";
1053 info->input->phys = "arizona/extcon";
1054 info->input->dev.parent = &pdev->dev;
1055
1016 if (pdata->num_micd_configs) { 1056 if (pdata->num_micd_configs) {
1017 info->micd_modes = pdata->micd_configs; 1057 info->micd_modes = pdata->micd_configs;
1018 info->micd_num_modes = pdata->num_micd_configs; 1058 info->micd_num_modes = pdata->num_micd_configs;
@@ -1068,6 +1108,66 @@ static int arizona_extcon_probe(struct platform_device *pdev)
1068 arizona->pdata.micd_dbtime 1108 arizona->pdata.micd_dbtime
1069 << ARIZONA_MICD_DBTIME_SHIFT); 1109 << ARIZONA_MICD_DBTIME_SHIFT);
1070 1110
1111 BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
1112
1113 if (arizona->pdata.num_micd_ranges) {
1114 info->micd_ranges = pdata->micd_ranges;
1115 info->num_micd_ranges = pdata->num_micd_ranges;
1116 } else {
1117 info->micd_ranges = micd_default_ranges;
1118 info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
1119 }
1120
1121 if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
1122 dev_err(arizona->dev, "Too many MICD ranges: %d\n",
1123 arizona->pdata.num_micd_ranges);
1124 }
1125
1126 if (info->num_micd_ranges > 1) {
1127 for (i = 1; i < info->num_micd_ranges; i++) {
1128 if (info->micd_ranges[i - 1].max >
1129 info->micd_ranges[i].max) {
1130 dev_err(arizona->dev,
1131 "MICD ranges must be sorted\n");
1132 ret = -EINVAL;
1133 goto err_input;
1134 }
1135 }
1136 }
1137
1138 /* Disable all buttons by default */
1139 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1140 ARIZONA_MICD_LVL_SEL_MASK, 0x81);
1141
1142 /* Set up all the buttons the user specified */
1143 for (i = 0; i < info->num_micd_ranges; i++) {
1144 for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
1145 if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
1146 break;
1147
1148 if (j == ARRAY_SIZE(arizona_micd_levels)) {
1149 dev_err(arizona->dev, "Unsupported MICD level %d\n",
1150 info->micd_ranges[i].max);
1151 ret = -EINVAL;
1152 goto err_input;
1153 }
1154
1155 dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
1156 arizona_micd_levels[j], i);
1157
1158 arizona_micd_set_level(arizona, i, j);
1159 input_set_capability(info->input, EV_KEY,
1160 info->micd_ranges[i].key);
1161
1162 /* Enable reporting of that range */
1163 regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
1164 1 << i, 1 << i);
1165 }
1166
1167 /* Set all the remaining keys to a maximum */
1168 for (; i < ARIZONA_MAX_MICD_RANGE; i++)
1169 arizona_micd_set_level(arizona, i, 0x3f);
1170
1071 /* 1171 /*
1072 * If we have a clamp use it, activating in conjunction with 1172 * If we have a clamp use it, activating in conjunction with
1073 * GPIO5 if that is connected for jack detect operation. 1173 * GPIO5 if that is connected for jack detect operation.
@@ -1095,20 +1195,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)
1095 1195
1096 arizona_extcon_set_mode(info, 0); 1196 arizona_extcon_set_mode(info, 0);
1097 1197
1098 info->input = devm_input_allocate_device(&pdev->dev);
1099 if (!info->input) {
1100 dev_err(arizona->dev, "Can't allocate input dev\n");
1101 ret = -ENOMEM;
1102 goto err_register;
1103 }
1104
1105 for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
1106 input_set_capability(info->input, EV_KEY,
1107 arizona_lvl_to_key[i].report);
1108 info->input->name = "Headset";
1109 info->input->phys = "arizona/extcon";
1110 info->input->dev.parent = &pdev->dev;
1111
1112 pm_runtime_enable(&pdev->dev); 1198 pm_runtime_enable(&pdev->dev);
1113 pm_runtime_idle(&pdev->dev); 1199 pm_runtime_idle(&pdev->dev);
1114 pm_runtime_get_sync(&pdev->dev); 1200 pm_runtime_get_sync(&pdev->dev);